System.in
是提供用户输入数据的“标准”输入流。关闭后,无法重新打开此流。一个这样的例子是在使用扫描仪读取用户输入的情况下如下:
public class Test {
public static void main(String[] args) {
boolean finished;
do {
Scanner inputScanner = new Scanner(System.in);
finished = inputScanner.hasNext("exit");
boolean validNumber = inputScanner.hasNextDouble();
if (validNumber) {
double number = inputScanner.nextDouble();
System.out.print(number);
} else if (!finished) {
System.out.println("Please try again.");
}
inputScanner.close();
} while (!finished);
}
}
在此示例中,创建了类型Scanner
的实例,并用于从用户读取一系列数字(请忽略此代码的其他详细信息,超出此示例的范围,我知道扫描程序应该在循环外创建和关闭)。在从用户输入检索到数字之后,关闭此Scanner
的实例(即,输入流)。但是,当从用户请求另一个号码并创建新实例时,无法再次打开输入流。在这个例子中,它创建了一个无限循环。
问题是:为什么不能重新打开封闭的流?
答案 0 :(得分:27)
为什么不能在Java中重新打开一个封闭的流?
这仅仅是Java流所代表的底层操作系统结构的本质。流本质上是一个数据管道。关闭它后,它就不再存在了。您可以在相同的端点之间创建一个新端点,但这会产生一个根本不同的流。我们可以考虑缓冲和流定位等实现注意事项,但这些都是边缘问题。
您还特别询问了标准流。这些是您无法重新创建的一些情况。操作系统为每个进程提供一组标准流。一旦它们关闭,就无法获得等价物。您可以在其位置放置不同的流,但无法将它们连接到原始端点。
答案 1 :(得分:9)
关闭标准输入流时:
如果您的输入是由管道提供的,则会通知管道的另一端。它将结束并停止发送数据。没有办法告诉你你犯了一个错误,它应该再次开始发送;
如果您的输入是由文件提供的,则操作系统会删除对该文件的引用,并完全忘记您正在使用它。您无法重新打开标准输入并继续阅读;
如果您的输入是由控制台提供的,则它适用于管道。控制台会收到通知,将关闭管道末端并停止向您发送数据。
所以没有办法重新打开标准输入。
但是......也没有理由关闭标准输入,所以不要这样做!
一个好的模式是:
打开文件的代码或类负责关闭它。
如果将InputStream传递给另一个从中读取的方法,则该方法不将其关闭。把它留给打开它的代码。它就像溪流所有者。
同样,如果将OutputStream传递给另一个写入它的方法,该方法应该不关闭它。将其留给拥有它的代码。但是如果你把流包装在其他可以缓冲一些数据的类中,那么做就会调用.flush()来确保一切都出来!
如果您正在围绕InputStream和OutputStream编写自己的包装类,不要关闭终结器中的委托流。如果在GC期间需要清理流,则应自行处理。
在您的示例代码中,不要关闭该扫描仪。您没有打开标准输入,因此您不需要关闭它。
答案 2 :(得分:3)
因为Streams是无界的。您可以根据需要从流中查看值。然后完成后只需关闭它。 Streams不会保留内存中的所有数据。流被设计为处理相对大量的数据,这些数据不能保存在存储器中。因此,您无法重新打开流,因为您已经对其进行了循环并耗尽了所有数据。因为流不会将这些数据保存在内存中。他们只是迷失了,这就是为什么你不能重新打开它。创建新流比创建现有流更好。
答案 3 :(得分:0)
Java标准库选择了标准化的"接近InputStream
。即使您可以合理地感知某些流(例如从输入控制台传入的数据),逻辑上可重新打开,InputStream
代表一种通用方法,因为它旨在涵盖所有可能的InputStream
,其中许多人本质上不可重新开放。正如在JohnBollinger的回答中所描述的那样。