Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is not possible to reopen a closed (standard) stream?

Tags:

java

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?

like image 397
Andrei Avatar asked Nov 05 '15 21:11

Andrei


People also ask

Why must a stream be closed when you are done using it?

Most streams must be closed when you are done with them, otherwise you could introduce a memory leak or leave a file open. It is important that streams are closed even if an exception is thrown.

What happens if input stream is not closed?

The operating system will only allow a single process to open a certain number of files, and if you don't close your input streams, it might forbid the JVM from opening any more.

How do you reopen a Java system?

It is not possible to reopen System.in , System. out or System. err . The underlying native streams are file descriptors that are connected to other processes, or to files whose identity your application cannot discern.

Does Inputstreamreader need to be closed?

Therefore, if you close the Reader, you don't need to also close the InputStream.


2 Answers

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.

like image 87
John Bollinger Avatar answered Sep 23 '22 08:09

John Bollinger


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.

like image 21
Matt Timmermans Avatar answered Sep 24 '22 08:09

Matt Timmermans