为什么不能重新打开封闭(标准)流?

And*_*rei 26 java

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

在此示例中,Scanner创建了一个类型实例,用于从用户读取一系列数字(请忽略此代码的其他详细信息,超出此示例的范围,我知道应在循环外创建并关闭扫描程序).在从用户输入检索到数字之后Scanner,关闭该实例(即,输入流).但是,当从用户请求另一个号码并创建新实例时,无法再次打开输入流.在这个例子的情况下,它创建一个无限循环.

问题是:为什么不能重新打开封闭的流?

Joh*_*ger 30

为什么不可能在Java中重新打开一个封闭的流?

这只是Java流所代表的底层操作系统结构的本质.流本质上是一个数据管道.关闭它后,它就不再存在了.您可以在相同的端点之间创建一个新的端点,但这会产生一个根本不同的流.我们可以考虑缓冲和流定位等实现注意事项,但这些都是边缘问题.

您还具体询问了标准流.这些是您无法重新创建的一些情况.操作系统为每个进程提供一组标准流.一旦它们关闭,就无法获得等价物.您可以在其位置放置不同的流,但无法将它们连接到原始端点.

  • 正如我所说,如果你有一个流的端点,那么你*可以*能够在这些相同的端点之间创建一个替换流.但是对于标准流,您只知道一个端点:您自己的程序.或者以您的Web服务器为例:*服务器*无论何时结束关闭它,都无法使用客户端重新建立流.就此而言,即使是客户也无法做到这一点.假设服务器是负载平衡服务器场的一部分.如果客户端发出新请求,则它可能不会转到同一物理服务器. (2认同)

Mat*_*ans 10

关闭标准输入流时:

  • 如果您的输入是由管道提供的,则会通知管道的另一端.它将结束并停止发送数据.没有办法告诉你你犯了一个错误,它应该再次开始发送;

  • 如果您的输入是由文件提供的,则操作系统会删除对该文件的引用,并完全忘记您正在使用它.您无法重新打开标准输入并继续阅读;

  • 如果您的输入是由控制台提供的,则它适用于管道.通知控制台,将关闭管道的末端并停止向您发送数据.

所以没有办法重新打开标准输入.

但是......也没有理由关闭标准输入,所以就这样做吧!

一个好的模式是:

  • 打开文件的代码或类负责关闭它.

  • 如果你传递一个InputStream到从读取另一种方法,该方法应该不会关闭它.把它留给打开它的代码.这就像溪流所有者.

  • 同样,如果你传递一个OutputStream一个写入到它的另一种方法,该方法应该不会关闭它.将其留给拥有它的代码.但如果你换其他类流是可以缓冲一些数据)呼吁他们.flush(以确保一切都出来!

  • 如果您正在围绕InputStream和OutputStream编写自己的包装类,请不要关闭终结器中的委托流.如果在GC期间需要清理流,它应该自己处理.

在您的示例代码中,只是不要关闭该扫描程序.您没有打开标准输入,因此您不需要关闭它.