29

System.in is the "standard" input stream which supplies user input data. Once closed, this stream can not be re-opened. One such example is in the case of using a scanner to read the user input as follows:

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);
    }
}

In this example, an instance of type Scanner is created and used to read a series of numbers from the user (please ignore other details with this code which go beyond the scope of this example, I know the scanner should be created and closed outside the loop). After a number is retrieved from user input, the instance of this Scanner (i.e., the input stream) is closed. However, when another number is requested from user, and new instance is created, the input stream cannot be opened again. In case of this example, it creates a infinite loop.

The question is: why is not possible to reopen a closed stream?

Andrei
  • 5,858
  • 6
  • 29
  • 60
  • Because its resources have already been released back to the operating system. Why aren't you opening the scanner and closing it outside the loop? – RealSkeptic Nov 05 '15 at 21:46
  • I'll just link your [previous question](http://stackoverflow.com/questions/33552505/scanner-continuous-loop). Both questions aren't duplicates, because on the 1st one the question was "why my Scanner isn't blocked after each iteration". But there are some useful tips and explanations which might be useful for future readers about the question here asked "Why you cannot reopen a closed stream". – Frakcool Nov 05 '15 at 21:51

4 Answers4

32

why is not possible to reopen a closed stream in Java?

That's simply the nature of the underlying operating system constructs that Java streams represent. A stream is essentially a data conduit. Once you close it, it no longer exists. You may be able to create a new one between the same endpoints, but that yields a fundamentally different stream. We could go into implementation considerations such as buffering and stream positioning, but those are really side issues.

You also asked specifically about the standard streams. These are some of the cases that you cannot recreate. The operating system provides each process with its set of standard streams. Once they are closed, there is no way to obtain equivalents. You can put different streams in their place, but you cannot connect them to the original endpoints.

John Bollinger
  • 121,924
  • 8
  • 64
  • 118
  • I can agree with the fact that once you close a stream, it no longer exists. However, the user or the java process should have a dedicated stream that it can use or not ("dedicated" here is too heavy). Based on endpoints, the user should be able to recreate the stream. Seems reasonable enough, and it happens in typical client-server architecture. I can load a webpage, and glue my fingers to CTRL+R keys, and the server will still get accept new requests from clients. I have the endpoints, I should be able to recreate the stream. What am I missing? – Andrei Nov 06 '15 at 00:48
  • 2
    As I said, If you have the endpoints of a stream then you *may* be able to create a replacement stream between those same endpoints. But with the standard streams, you know only one endpoint: your own program. Or take your web server example: the *server* cannot reestablish a stream with a client once either end closes it. Even the client cannot be certain of doing so, for that matter. Suppose the server is part of a load-balanced server farm. If the client issues a new request then it might not go to the same physical server. – John Bollinger Nov 06 '15 at 13:58
  • More generally, any stream that is involved in IPC, which includes the standard streams much of the time, must be established cooperatively by the processes involved. Once such a stream is closed, by either side, it cannot be unilaterally recreated. – John Bollinger Nov 06 '15 at 14:04
  • 1
    You may want to examine a Filter stream that maps the `close()` operation to a nop. As others have already answered, the stream itself is destroyed and not recoverable. The file that provided it may have been deleted when you closed it, the network connection ended. – Norwæ Nov 18 '15 at 11:31
11

When you close the standard input stream:

  • If your input was being provided by a pipe, the other end of the pipe is notified. It will close its end and stop sending data. There is no way to tell it you made a mistake and it should start sending again;

  • If your input was being provided by a file, the OS drops its reference to the file and completely forgets that you were using it. There is just no way provided for you to reopen standard input and continue reading;

  • If your input was being provided by the console, it works with a pipe. The console is notified, will close its end of the pipe and stop sending you data.

So there's no way to reopen standard input.

BUT... there is also no reason to close standard input, so just don't do that!

A good pattern to follow is:

  • The code or class that opens a file is responsible for closing it.

  • If you pass an InputStream to another method that reads from it, that method should not close it. Leave that to the code that opened it. It's like the streams owner.

  • Similarly, if you pass an OutputStream to another method that writes to it, that method should not close it. Leave that to the code that owns it. BUT if you wrap the stream in other classes that may buffer some data do call .flush() on them to make sure everything comes out!

  • If you're writing your own wrapper classes around InputStream and OutputStream, don't close the delegate stream in your finalizer. If a stream needs to be cleaned up during GC, it should handle that itself.

In your example code, just don't close that Scanner. You didn't open standard input, so you shouldn't need to close it.

Matt Timmermans
  • 36,921
  • 2
  • 27
  • 59
  • With re-open, I mean to create a stream. I understand from all the answers that it is not possible to re-open because you lose the initial references to the end points. However, if we look at the sample code above, every time the loop is executed, it should create a new stream. Think about your browser and an internet page. If you load that page once, what holds you back from refresing the page? – Andrei Nov 18 '15 at 09:59
  • The difference is that your browser has an URL that tells it how to get at the page. Your process doesn't have any information about what its standard input file refers to. The underlying file is actually opened by the parent process (the one that creates yours), and you just get a handle to the open file. That's a a number that identifies the file in the OS. It's not a set of instructions for creating a stream, like an URL is. – Matt Timmermans Nov 18 '15 at 13:37
4

Because Streams are unbounded. You peek values from streams as you need. Then when done simply close it. Streams does not hold it's all data in memory. Streams are designed to process relatively big amount of data which can't be held in memory. So you can't reopen an stream simply because you already have made a loop over it and exhausted all the data. As stream does not hold those data in memory. They are simply lost and that's why you can't reopen it. The better is you create a new stream than reopen an existing one.

sohan nohemy
  • 547
  • 4
  • 13
0

Java standard library has chosen a "standardized" approach to InputStream. Even if you may legitimately perceive some streams, such as data incoming from the input console, as logically re-openable, the InputStream represents a generic approach, as it is intended to cover all the possible InputStreams, which many of them are by their nature not re-openable. As described perfectly in @JohnBollinger's answer.

Honza Zidek
  • 6,952
  • 4
  • 52
  • 82