I don't know if this is a noob question, but in my code:
void process() {
...
while (input.hasNext()) {
\\ DO WHATEVERITNEEDSTODO
}
out.close();
...
}
It does everything in the while statement, but afterwards it doesn't go on and therefore doesn't close. Even when I put System.out.println("Hello hello") instead of out.close() as a simple check, it doesn't print "Hello hello"
I'm basically trying to have out.close() happen after my input has gone through everything. Is there another way to do this?
Per the docs for hasNext(), "This method may block while waiting for input to scan." I'd guess you're running a Scanner on some kind of input that never ends (like maybe System.in?). Therefore, you'd see the body of the loop executing, but eventually, you run out of things to process, and it hangs forever waiting for there to either be a "next" or not.
To put it another way, just because there's nothing presently available to read from the Scanner's underlying stream, it doesn't mean there will never be. As long as the stream remains open, more content may eventually become available to be read.
Related
I'm trying to make a simple counter that starts between user inputs (3..., 2..., 1..., Go!).
try (var reader = new BufferedReader(new InputStreamReader(System.in))) {
...
try {
for (int i = 0; i < 3; i++) {
System.out.println(i + "...");
Thread.sleep(500);
}
System.out.println("Go!");
} catch (Exception e) {
e.printStackTrace();
}
...
}
The problem is Im still able to press keys between delays, which then gets printed. Is there a way to block BufferedReader while for-each works?
You cannot prevent the user pressing keys while he should be waiting.
For the same reason you cannot prevent your application to receive these characters through System.in up until the BufferedReader. Blocking that is the wrong approach.
What you can do however is ignore those keypresses. But you must prevent that they remain in the input buffer and get evaluated after your loop.
Since you are reading from stdin however, it is not your program to print the characters. I guess it is the terminal emulator that you use when running your console based application. And therefore I am unsure how you can prevent the echo to the console. What undermines my assumption is
https://forums.codeguru.com/showthread.php?466009-Reading-from-stdin-(without-echo)
What proves I am wrong (and what you should try out therefore) is
How to use Scanner to read silently from STDIN in Java?
or more general
https://www.geeksforgeeks.org/ways-to-read-input-from-console-in-java/
Both recommend to suppress the echo by reading from System.console().
Your problem is not related to the BufferedReader, and the solution is probably more complex than what you imagined.
When you run your Java process, it is usually connected to a terminal. This terminal (or emulator) handles your keyboard and usually provides your input line by line to the attached process. The terminal also echos characters as you type. Meaning the Java process does not print the characters you type, you therefor can't prevent them being printed from within the your process.
Terminals and terminal control is highly platform specific. On Linux system you can control the terminal using termios. The flags you want to be disable is ECHO for echoing your keystrokes and ICANON to disable canonical mode so you'd receive input as soon as it is available. You'd have to perform this before your loop. After or in your loop you'd have to consume any input and discard it, enable ECHO and ICANON again. Be aware though that the BufferedReader might have something buffered already and is performing blocking I/O.
termios however is not directly accessible from Java, calls would have to be wrapped through JNI f.i. A quick google search came up with a library called purejavacomm
I have a GUI program written in Java which outputs data to the command line using System.out.println. The data is intended to be piped into another program. As an example, I'll pipe the program through head:
$ java MyProgram | head -n10
I want my program to exit when the pipe is broken: in this case, this should happen after MyProgram has printed out ten lines of text.
There is a similar question on this site, and the solution given there works fairly well; for example, I could have the following running in its own thread:
while(!System.out.checkError()) {
// sleep 100ms
}
System.exit(0);
The problem is that PrintStream.checkError() seems to return true only after you have tried to print to the stream and failed. For that reason, my program does not in fact exit until it has printed out eleven lines of text: the pipe is broken after the first ten, but System.out continues to return true until I try to pipe through the eleventh line.
Printing out extra 'junk' lines in order to trigger an error on the PrintStream is out of the question, since the program on the right hand side of the pipe may be very sensitive to the data it receives.
Calling System.out.flush() inside the loop has no effect on PrintStream.checkError(), even though the source code for PrintStream indicates that it ought to call the private ensureOpen method in that class.
How can I reliably test whether System.out is open without printing anything to it?
'Real world' example: suppose that I have some program consumer that takes in command line input and does something with it. Certain pieces of input will call consumer to fail silently. Since the input to consumer is sometimes long and abstruse, I write a GUI program InputProvider in Java where I can click buttons and have the corresponding commands printed out to stdout. If I pipe the output of InputProvider into consumer, then I am able to control consumer graphically.
Unfortunately, there seems to be no way for InputProvider to notify the user when consumer has shut down, except by attempting to write to consumer and getting an exception of some kind.
I don't think you can fix this in Java. There's nothing wrong with System.out until you write to it and it fails. Another process (head) ended but the Java process can't know about that.
So I think that you have two options.
don't use pipe to head but limit the output in your Java code - then you'll know when to stop
accept that the last line will fail and handle the exception appropriately
Try to set a new stream for the system that way you'll be able to check if that stream is closed or not: OutputStream output = new FileOutputStream("c:\\data\\system.out.txt"); and PrintStream printOut = new PrintStream(output);. Then set it here: System.setOut(printOut); and inside the if you can check if(printOut.checkError())
When my program starts, it opens a file and writes to it periodically. (It's not a log file; it's one of the outputs of the program.) I need to have the file available for the length of the program, but I don't need to do anything in particular to end the file; just close it.
I gather that for file I/O in Java I'm supposed to implement AutoCloseable and wrap it in a try-with-resources block. However, because this file is long-lived, and it's one of a few outputs of the program, I'm finding it hard to organize things such that all the files I open are wrapped in try-with-resources blocks. Furthermore, the top-level classes (where my main() function lies) don't know about this file.
Here's my code; note the lack of writer.close():
public class WorkRecorder {
public WorkRecorder(String recorderFile) throws FileNotFoundException {
writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(recorderFile)));
}
private Writer writer;
public void record(Data data) throws Exception {
// format Data object to match expected file format
// ...
writer.write(event.toString());
writer.write(System.lineSeparator());
writer.flush();
}
}
tl;dr do I need to implement AutoCloseable and call writer.close() if the resource is an opened output file, and I never need to close it until the program is done? Can I assume the JVM and the OS (Linux) will clean things up for me automatically?
Bonus (?): I struggled with this in C#'s IDisposeable too. The using block, like Java's try-with-resources construct, is a nice feature when I have something that I'm going to open, do something with quickly, and close right away. But often that's not the case, particularly with files, when the access to that resource hangs around for a while, or when needing to manage multiple such resources. If the answer to my question is "always use try-with-resources blocks" I'm stuck again.
I have similar code that doesn't lend itself to being wrapped in a try-with-resources statement. I think that is fine, as long as you close it when the program is done.
Just make sure you account for any Exceptions that may happen. For example, in my program, there is a cleanup() method that gets called when the program is shut down. This calls writer.close(). This is also called if there is any abnormal behavior that would cause the program to shut down.
If this is just a simple program, and you're expecting the Writer to be open for its duration, I don't think it's really a big deal for it to not be closed when the program terminates...but it is good practice to make sure your resources are closed, so I would go ahead and add that to wherever your program may shut down.
You should always close resources or set them to null so it can be picked up by the garbage collector in Java. Using try-with-resource blocks is a great way to have Java automatically close resources when you're done with them. Even if you use it for the duration of the program, it is good programming practice to close it even at the end. Some might say you don't need to, I personally would say just go ahead and do it and here's why:
"When a stream is no longer needed, always close it using the close() method or automatically close it using a try-with-resource statement. Not closing streams may cause data corruption in the output file, or other programming errors."
-Introduction to Java Programming 10th Edition, Y. Daniel Liang
If possible, just run the .close() method on the resource at the very end of the program.
I (now) think a better answer is "It depends" :-). A detailed treatment is provided by Lukas Eder here. Also check out the Lambda EG group post.
But in general, it's a good idea to return the resource back to the operating system when you are done with it and use try-with-resources all the time (except when you know what you are doing).
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.
I'm trying to implement asynchronous input reading from console in Java.
Basically, I want to do this:
Spawn a thread T which reads on standard input with a readLine() on a BufferedReader
Continue with the program
After 10 seconds, stop T
The problem is the readLine() call in T, which I haven't been able to block.
Since interrupting the thread does not work, I figured I would try and send data to standard input from code, to unblock the readLine().
So I tried the following: after 10 seconds, do
FileOutputStream os = new FileOutputStream(FileDescriptor.in);
os.write("Unblocking line\n");
I thought it would work like this: I'm writing to the standard input as in a pipe, so the code in T should read "Unblocking line\n" and go to the next instruction.
Too bad, this doesn't work: "Unblocking line" is immediately shown on screen as if it was written to standard output, and it doesn't seem to affect the readLine().
So my questions are:
Why is my reasoning wrong?
Is there a simple, clean method to achieve what I want to do? Please note that I'm aware of this solution. Also, please do not suggest using System.setIn: it doesn't work. Finally, I should clarify what I mean by simple and clean: using only threads, and avoiding busy waiting.
Thanks in advance.
EDIT: I don't want to close the standard input, as I want to read again after step #3.
Have you tried to simply call
System.in.close() ?
readLine() has to wait for a user to enter some thing. forever if nothing entered.
In your case, you want the thread to close automatically after 10 seconds if nothing entered I think!
code your thread accordingly. Instead of waiting forever if 10 seconds went without user entering an input then main thread should close input waiting thread.