System.out关闭了吗? 我可以重新打开吗?
我正在帮朋友写一些Java代码,他们对Java知之甚少。 所以我给他写了一些辅助函数来轻松完成他眼中有点古怪的事情。 其中一个是函数,它将String写入OutputStream
。 看一看:
public void write(String txt, OutputStream out) { PrintWriter printer = new PrintWriter(out); printer.print(txt); printer.close(); }
现在,您可以通过不同的方式轻松地使用它来编写您想要的任何位置。 例如,你可以这样做:
(new StreamHelper()).write("Hello Test", System.out);
这样做我发现之后System.out.println()
不再向shell写入任何内容。 所以我认为也许printer.close()
自动也关闭System.out
,我想知道如何重新激活它,我可以在此function再次完成后使用它。
我的假设是否正确? (如果不问这里我怎么能找到?)
在调用write()
函数后如何继续使用System.out
?
是否有更好的方法来编写这样的辅助函数?
OutputStream
关闭的一般合约:
public void close()throws IOException关闭此输出流并释放与此流关联的所有系统资源。 close的一般合同是它关闭输出流。 封闭流无法执行输出操作, 无法重新打开 。
PrintStream
的
public void close()关闭流。 这是通过刷新流然后关闭底层输出流来完成的 。
我可以给你的唯一建议是你不应该编写不对称的代码 ,也就是说,不要将代码创建的资源关闭委托给其他地方。
即使在你的情况下,关闭包装器流似乎也是明智的,事实是你不应该因为你正在关闭在其他地方打开的流。
简而言之:
public void write(String txt, OutputStream out) { PrintWriter printer = new PrintWriter(out); printer.print(txt); printer.flush(); //it is very unpolite to close someone else's streams! //printer.close(); }
哦,顺便说一下,你可能想要更改函数名称来print
,而不是write
。
就像其他人所说的那样,流应该在打开的地方关闭。 但是,您可以编写一个外观来保护流不被关闭,如下所示:
import java.io.FilterOutputStream; import java.io.IOException; import java.io.OutputStream; public class UnclosableOutputStream extends FilterOutputStream { public UnclosableOutputStream(OutputStream out) { super(out); } @Override public void close() throws IOException { out.flush(); } }
并像这样使用它:
new StreamHelper().write("Hello Test", new UnclosableOutputStream(System.out));
对于测试场景等可能会派上用场。
System.out
是一个PrintStream,因此上面提供的代码实际上没有直接调用System.out.print
优势。 它不再写的原因是, close
实际上是关闭了System.out
。
如果这是用于记录,请为您的朋友学习log4j或帮助他学习它。 Log4j可以处理需要同时写入文件流,标准输出等的情况。
您可以检查传递的输出是否是System.out
并有选择地决定不关闭。
flush()
调用是必要的。 请注意,我正在进行==
检查,因为如果您使用System.out
参数调用此write
方法,则引用将是相同的。
public void write(String txt, OutputStream out) { PrintWriter printer = new PrintWriter(out); printer.print(txt); printer.flush(); if(out != System.out) { printer.close(); } }
但说实话,我会保留一种不同的方法来关闭或调用此方法writeAndClose
以避免混淆。
如果你想保持抽象(如@Urs暗示的那样),请执行以下操作。 但是,我认为这并不是过度工程化的重点
public void write(String txt, OutputStream out) { PrintWriter printer = new PrintWriter(out); printer.print(txt); printer.flush(); } public void close(OutputStream out) { out.close(); }
按照Stas Kurilin的建议行事。
通常,流应该由打开/创建它们的一方关闭。
在您的方法中,只需刷新流。 在不再需要它的时候关闭它。
让我们从调用者的角度来看这个。
调用者有一个类型的OutputStream
,并调用一个名为write()
的方法。 呼叫完成后,呼叫者发现该流已关闭。
在我看来,你的write()
方法根本不应该调用printer.close()
。 后者关闭调用者提供的流,可能不是调用者所期望的。
如果需要刷新流,可以使用flush()
。
如果要在JVM控制台上尝试输出,最好使用System.console()
获取控制台实例。 然后使用console.writer()
方法获取PrintWriter
。 使用PrintWriter
,您可以关闭它。 基于JavaDoc的控制台描述,
在
reader()
和writer()
返回的对象上调用close()
将不会关闭这些对象的基础流。
你可以一次又一次地这样做。 无需担心重新打开流。