How to system.in reopen in java? [duplicate] - 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?

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.

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.

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.

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.

Related

Should I close a stream which I did not create?

If I have stream (InputStream or OutputStream) which I did not create but was rather passed to my method as a parameter, should I be closing that stream? Here's an example:
void method(InputStream in) {
try {
//Do something
}
finally {
if(in != null) {
in.close(); //Is this needed and correct?
}
}
Really, "it depends".
As a general rule, you should not close a stream that you didn't have responsibility for opening, but to give a correct answer we would have to understand the context.
It's very possible that the delegation of responsibility requires your method to consume from and close the stream - if this is the case then it should be explicit in the code.
If your method is named readFromStreamAndClose(InputStream in) then the fact that your method closes the stream is very obvious.
In the case that you open the stream yourself, you can always use a try-with-resources block which will close the stream for you - at the same level of abstraction as it was created. In this case - your method (which is called at a lower level than when the stream was opened) should not close the stream.
Generally it is not recommended to close the stream which is not associated to that class.
Following are the reasons,
Streams passed to that method may be used in some other place.
Reusable streams are available in java. If the stream is closed it
cannot be reopened and reused.
In case of Exception when closing the stream you don't know how to
handle that. Because you are dealing with general inputstream and it
may come from any place like File, Network etc.
The class opens the stream is responsible for closing it.
I don't think that the JVM spec makes any guarantee about that. You really are supposed to finally close these resources.
When the process ends, the operating system will release all resources associated to it (including memory, file handles, and network sockets).
There are OS facilities to check about open files and streams
No you don't have to do it because it may be used somewhere further in the code.
You do document the method with: "Closes the stream" and change the name method to like readAndClose.
Or create a parameter boolean closeStream and close if true.
Also if the stream doesnt support mark/seek/reset there's no reason to keep it open.

Reuse an InputStream to a Process in Java

I am using ProcessBuilder to input and receive information from a C++ program, using Java. After starting the process once, I would like to be able to input new strings, and receive their output, without having to restart the entire process. This is the approach I have taken thus far:
public void getData(String sentence) throws InterruptedException, IOException{
InputStream stdout = process.getInputStream();
InputStreamReader isr = new InputStreamReader(stdout);
OutputStream stdin = process.getOutputStream();
OutputStreamWriter osr = new OutputStreamWriter(stdin);
BufferedWriter writer = new BufferedWriter(osr);
BufferedReader reader = new BufferedReader(isr);
writer.write(sentence);
writer.close();
String ch = reader.readLine();
preprocessed="";
while (ch!=null){
preprocessed = preprocessed+"~"+ch;
ch = reader.readLine();
}
reader.close();
}
Each time I want to send an input to the running process, I call this method. However, there is an issue: the first time I send an input, it is fine, and the output is received perfectly. However, the second time I call it, I receive the error
java.io.IOException: Stream closed
which is unexpected, as everything is theoretically recreated when the method is called again. Moreover, removing the line the closes the BufferedWriter results in the code halting at the following line, as if the BufferedReader is waiting for the BufferedWriter to be closed.
One final thing - even when I create a NEW BufferedWriter and instruct the method to use that when called for the second time, I get the same exception, which I do not understand at all.
Is there any way this can be resolved?
Thanks a lot!
Your unexpected IOException happens because when Readers and Writers are closed, they close their underlying streams in turn.
When you call your method the first time, everything appears to work. But you close the writer, which closes the process output stream, which closes stdin from the perspective of the process. Not sure what your C++ binary looks like, but probably it just exits happily when it's done with all its input.
So subsequent calls to your method don't work.
There's a separate but similar issue on the Reader side. You call readLine() until it returns null, meaning the Reader has felt the end of the stream. But this only happens when the process is completely done with its stdout.
You need some way of identifying when you're done processing a unit of work (whatever you mean by "sentence") without waiting for the whole entire stream to end. The stream has no concept of the logical pause between outputs. It's just a continuous stream. Reader and Writer are just a thin veneer to buffer between bytes and characters but basically work the same as streams.
Maybe the outputs could have delimiters. Or you could send the length of each chunk of output before actually sending the output and distinguish outputs that way. Or maybe you know in advance how long each response will be?
You only get one shot through streams. So they will have to outlive this method. You can't be opening and closing streams if you want to avoid restarting your process every time. (There are other ways for processes to communicate, e.g. sockets, but that's probably out of scope.)
On an orthogonal note, appending to a StringBuilder is generally more efficient than a big loop of string concatenations when you're accumulating your output.
You might also have some thread check process.exitValue() or otherwise make sure the process is working as intended.
Don't keep trying to create and close your Streams, because once you close it, it's closed for good. Create them once, then in your getData(...) method use the existing Streams. Only close your Streams or their wrapping classes when you're fully done with them.
Note that you should open and close the Streams in the same method, and thus may need additional methods or classes to help you process the Streams. Consider creating a Runnable class for this and then reading from the Streams in another Thread. Also don't ignore the error stream, as that may be sending key information that you will need to fully understand what's going on here.

how to reopen and interrupt keyboard stream?

I have a very simple question.
Based on Java I/O scheme, whenever a thread is waiting for some data, so it will be blocked? is it true? something like this.
byte[] _buff=new byte[1024];
int _r=_in.read(_buff);//it blocks until some data is available
and the just possible way to give up reading is closing the stream by another thread, is it right? something like this.
void run(){
_in.close();
}
so if I am right with above scenarios, so why this is impossible just interrupt a thread which is reading from System.in by closing the stream. I run a thread that just waits for 5 seconds then wants to interrupt/give up rest of the reading from the stream.
void _read_data(){
System.out.print("enter y to save the workspace ");
new Thread(_cancel_thread).start();
int _r=System.in.read();//blocks
}
///////////
void run(){
try{
Thread.sleep(5000);
System.in.close();//doesn't work.
}catch(Exception _ex){}
}
Questions:
1.How to close the stream?! why the closing stream thread cannot close the stream?!
2.Once the stream got closed, how to open it again?!
For the first question, I think this is because maybe(I don't know, not sure) the stream is kinda locked by lower-level, so while it's locked, another thread is just waiting to acquire the lock and close it.
and for second one, I really don't know is there any class(stream) which works with keyboard stream or not, but why do you really want to close it? just keep the stream somewhere (like in=System.in), then redirect the standard stream to another stream by calling System.setIn(newStream), then whenever you want to give keyboard stream back, reset the stream with the reference.
Closing the default system input stream is not good idea, I suggest you utilize either JConsol or jNativeHook, these guys do not block, instead they listen for events.

when does FileInputStream.read() block?

The question is similar to the following two questions.
Java InputStream blocking read
Why is the FileInputStream read() not blocking?
But I still cannot fully understand it.
So far I think the read() method in following code will block due to the empty file 'test.txt'.
FileInputStream fis = new FileInputStream("c:/test.txt");
System.out.println(fis.read());
System.out.println("to the end");
Actually it will print -1, I want to know why.
The javadoc says This method blocks if no input is yet available.
What does 'no input is available' mean?
thanks.
The answer to your question can be found in the JavaDoc for .read():
This method blocks if no input is yet available.
and
Returns: the next byte of data, or -1 if the end of the file is reached.
So, an empty file will get you an immediate -1 (instead of read() blocking) as
there is input available, since the file exists
...but it is empty, so immediate EOF.
The ...No input is yet available... situation could occur eg. when one was to read from a named pipe instead of a plain file, and the other side of the pipe hasn't written anything yet.
Cheers,
FileInputStream can be used to read from things other than ordinary files. One obvious example is a named pipe: if you try to read from a pipe before the other side has written to it, the read operation will block.
This maybe interperted as follows: FileInputStream.read invokes a native method, the native method makes the read system call and blocks waiting for OS to read the bytes from file into a buffer and returns when ready. That is, FileInputStream.read uses synchronous I/O to reads data from a file as opposed to non-blocking, asynchronous I/O.
You can't interpret 'no input is available' as 'you are positioned at EOF and no more input will ever be available'. They are different conditions. The latter returns -1.
In general, all reads from files block until the data is available. The disk has to come around to the right point and the head has to seek to the right track. You also need to consider files that are on shared drives, or files that are named pipes, both of which involve network operations, which can also block.

FindBugs: "may fail to close stream" - is this valid in case of InputStream?

In my Java code, I start a new process, then obtain its input stream to read it:
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
FindBugs reports an error here:
may fail to close stream
Pattern id: OS_OPEN_STREAM, type: OS, category: BAD_PRACTICE
Must I close the InputStream of another process? And what's more, according to its Javadoc, InputStream#close() does nothing. So is this a false positive, or should I really close the input stream of the process when I'm done?
In this case, you want to close() the Reader, which will close its underlying streams. Yes, it's always good practice to close streams, even if at the moment you know the implementation you're looking at doesn't do anything (though, in fact, it does here!). What if that changed later?
FindBugs is only there to warn about possible errors; it can't always know for sure.
Finally yes, your Java process owns the process and Process object you spawned. You most definitely need to close that and the output stream. Nobody else is using them, and, it's important to do such things to avoid OS-related stream funny business.
InputStream is an abstract class - just because its implementation does nothing doesn't mean that the actual type of object returned by process.getInputStream() doesn't.
It's possible that failing to close the input stream in this particular case would do no harm - but I personally wouldn't count on it. Close it like you'd close any other input stream. Aside from anything else, that makes your code more robust in case you ever decide to change it to read from something else - it would be all too easy to (say) read from a file instead, and not notice that you're not closing the FileInputStream.
I think its always a good practice to close all the streams you open. Preferably in the finally{} block. Since it does nothing as java says, why not call the close() method. Its of no harm.

Categories

Resources