Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

In Java is it possible to re-open System.in after closing it

I have a multithreaded console app that gets input from two different sources. One is the user typing into the console and the other is the network. I use a BufferedReader.readline() to get input from the user and that blocks, which is good, unless I receive network input while I'm waiting. In that case I need to unblock the user thread by canceling readline().

I figured the best way to cancel that is to close System.in and make readline() throw an exception. After that though I'd need to re-open it. Is that possible?

like image 865
ForeverNoobie Avatar asked Dec 04 '14 05:12

ForeverNoobie


People also ask

Who is responsible for closing a file in Java?

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.

Why can't I re-open a closed issue?

Let's say your workflow already has transitions to re-open, but you can't reopen this closed issue. It's possible that the Closed status has a workflow property such as jira.issue.editable = false. If this is the case, users can't edit issues in that specific status.

Why can't I re-open a stream in Java?

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.

Is there a way to re-open standard input?

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! 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.


1 Answers

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. Once the underlying native file descriptors are closed, it is not possible to reopen them.

The best I can suggest is that you create a wrapper InputStream class for the System.in object, and code the wrapper to treat close() as a no-op. Or maybe set the wrapper into a "closed" state without actually closing the wrapped stream.

In your specific use-case, that won't work, because you "need" to unblock the thread that is blocked while reading from System.in. So in your case, you will need to do non-blocking input from System.in. For example, use the available() method to test if there are any characters to read from the console. (It is typically safe to assume that if available() returns a number greater than zero you will be able to read an entire line.)

(It might also be able to implement non-blocking reads using a Selector, but I don't think that it is possible to obtain a "selectable channel" for the System.in object.)


Note that Thread.interrupt() won't work. According to the javadocs, it will only work if you are reading from an interruptible channel.

  • System.in is not an interruptible channel, and

  • if it was, then the documented behaviour for interrupt() is that the channel gets closed by the interrupt.

like image 64
Stephen C Avatar answered Nov 14 '22 22:11

Stephen C