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()将不会关闭这些对象的基础流。

你可以一次又一次地这样做。 无需担心重新打开流。