I am executing a simple java application in eclipse.
Sample code:
BufferedReader input = new BufferedReader( new InputStreamReader(System.in));
String line;
while((line = input.readLine()) != null && line.length() != 0)
{
System.out.println("------"+line);
}
In the above code the readline() method hangs when reading the last line of my input.
I have gone through some threads and understood that it waits for the end of line.
I don't want to give any '\n' or '\r' at the end of my input in the console.
so how to handle this in the code.
How is the code to know when you are not going to type anything else unless you press enter?
There is no solution to this issue. You need to re-think your use-case.
Related
I have the following code example below. Whereby you can enter a command to the bash shell i.e. echo test and have the result echo'd back. However, after the first read. Other output streams don't work?
Why is this or am I doing something wrong? My end goal is to created a Threaded scheduled task that executes a command periodically to /bash so the OutputStream and InputStream would have to work in tandem and not stop working. I have also been experiencing the error java.io.IOException: Broken pipe any ideas?
Thanks.
String line;
Scanner scan = new Scanner(System.in);
Process process = Runtime.getRuntime ().exec ("/bin/bash");
OutputStream stdin = process.getOutputStream ();
InputStream stderr = process.getErrorStream ();
InputStream stdout = process.getInputStream ();
BufferedReader reader = new BufferedReader (new InputStreamReader(stdout));
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(stdin));
String input = scan.nextLine();
input += "\n";
writer.write(input);
writer.flush();
input = scan.nextLine();
input += "\n";
writer.write(input);
writer.flush();
while ((line = reader.readLine ()) != null) {
System.out.println ("Stdout: " + line);
}
input = scan.nextLine();
input += "\n";
writer.write(input);
writer.close();
while ((line = reader.readLine ()) != null) {
System.out.println ("Stdout: " + line);
}
Firstly, I would recommend replacing the line
Process process = Runtime.getRuntime ().exec ("/bin/bash");
with the lines
ProcessBuilder builder = new ProcessBuilder("/bin/bash");
builder.redirectErrorStream(true);
Process process = builder.start();
ProcessBuilder is new in Java 5 and makes running external processes easier. In my opinion, its most significant improvement over Runtime.getRuntime().exec() is that it allows you to redirect the standard error of the child process into its standard output. This means you only have one InputStream to read from. Before this, you needed to have two separate Threads, one reading from stdout and one reading from stderr, to avoid the standard error buffer filling while the standard output buffer was empty (causing the child process to hang), or vice versa.
Next, the loops (of which you have two)
while ((line = reader.readLine ()) != null) {
System.out.println ("Stdout: " + line);
}
only exit when the reader, which reads from the process's standard output, returns end-of-file. This only happens when the bash process exits. It will not return end-of-file if there happens at present to be no more output from the process. Instead, it will wait for the next line of output from the process and not return until it has this next line.
Since you're sending two lines of input to the process before reaching this loop, the first of these two loops will hang if the process hasn't exited after these two lines of input. It will sit there waiting for another line to be read, but there will never be another line for it to read.
I compiled your source code (I'm on Windows at the moment, so I replaced /bin/bash with cmd.exe, but the principles should be the same), and I found that:
after typing in two lines, the output from the first two commands appears, but then the program hangs,
if I type in, say, echo test, and then exit, the program makes it out of the first loop since the cmd.exe process has exited. The program then asks for another line of input (which gets ignored), skips straight over the second loop since the child process has already exited, and then exits itself.
if I type in exit and then echo test, I get an IOException complaining about a pipe being closed. This is to be expected - the first line of input caused the process to exit, and there's nowhere to send the second line.
I have seen a trick that does something similar to what you seem to want, in a program I used to work on. This program kept around a number of shells, ran commands in them and read the output from these commands. The trick used was to always write out a 'magic' line that marks the end of the shell command's output, and use that to determine when the output from the command sent to the shell had finished.
I took your code and I replaced everything after the line that assigns to writer with the following loop:
while (scan.hasNext()) {
String input = scan.nextLine();
if (input.trim().equals("exit")) {
// Putting 'exit' amongst the echo --EOF--s below doesn't work.
writer.write("exit\n");
} else {
writer.write("((" + input + ") && echo --EOF--) || echo --EOF--\n");
}
writer.flush();
line = reader.readLine();
while (line != null && ! line.trim().equals("--EOF--")) {
System.out.println ("Stdout: " + line);
line = reader.readLine();
}
if (line == null) {
break;
}
}
After doing this, I could reliably run a few commands and have the output from each come back to me individually.
The two echo --EOF-- commands in the line sent to the shell are there to ensure that output from the command is terminated with --EOF-- even in the result of an error from the command.
Of course, this approach has its limitations. These limitations include:
if I enter a command that waits for user input (e.g. another shell), the program appears to hang,
it assumes that each process run by the shell ends its output with a newline,
it gets a bit confused if the command being run by the shell happens to write out a line --EOF--.
bash reports a syntax error and exits if you enter some text with an unmatched ).
These points might not matter to you if whatever it is you're thinking of running as a scheduled task is going to be restricted to a command or a small set of commands which will never behave in such pathological ways.
EDIT: improve exit handling and other minor changes following running this on Linux.
I think you can use thread like demon-thread for reading your input and your output reader will already be in while loop in main thread so you can read and write at same time.You can modify your program like this:
Thread T=new Thread(new Runnable() {
#Override
public void run() {
while(true)
{
String input = scan.nextLine();
input += "\n";
try {
writer.write(input);
writer.flush();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
} );
T.start();
and you can reader will be same as above i.e.
while ((line = reader.readLine ()) != null) {
System.out.println ("Stdout: " + line);
}
make your writer as final otherwise it wont be able to accessible by inner class.
You have writer.close(); in your code. So bash receives EOF on its stdin and exits. Then you get Broken pipe when trying to read from the stdoutof the defunct bash.
in = new DataInputStream(conn.getInputStream());
String str = "";
while (in.available() > 0) {
str += in.readUTF();
}
in = new DataInputStream(conn.getInputStream());
String str = "";
while (in.available() > 0) {
str2 += Bytes.toString(in.readBytes());
}
I cannot read any response from my php page with two methods above.
in = new BufferedReader(new InputStreamReader(conn.getInputStream(), "UTF-8"));
String str2="";
while ( (str += in.readLine()) != null && in.ready()){}
And only this method can works.
Can someone tell me what it is happening either there's the problem of inputstream ,type or charset. Thanks!!
readUTF() can only read data that was written by writeUTF(). Unless you know that the server is sending data in that format you should not use it. It isn't a general-purpose string-reading method.
Possibly you're looking for BufferedReader.readLine(), but without knowing your application payload protocol it is impossible to be sure.
while ( (str += in.readLine()) != null && in.ready()){}
+= is the wrong operation here. It makes it impossible for the following null test to ever be true. Use =, and append inside the loop. The ready() test is futile here too. What you're testing here is (a) a line was returned and (b) some further data is pending ready to be read without blocking. You don't care about (b). Remove that. You probably meant to write the tests in the opposite order, but it would still be futile. Just block in readLine(). Set a read timeout if you don't entirely trust the server.
I am trying to run a linux command in java code. The command is raspivid which I have placed on the server under test.sh file for live camera streaming. Everything works fine but the problem is the streaming stops after some minutes after starting the tomcat server. Like the streaming stops after 6-7 minutes while running the command in java but at the background the raspivid process is running. On the other hand when I run the same command without using java code it works fine. Is this an issue of tomcat heap or anything else which stops the streaming? Please help see the below code:
try {
Process p = Runtime.getRuntime().exec(new String[]{"sudo","sh","/home/pi/test.sh"});
BufferedReader stdInput = new BufferedReader(new
InputStreamReader(p.getInputStream()));
BufferedReader stdError = new BufferedReader(new
InputStreamReader(p.getErrorStream()));
// read the output from the command
LOGGER.info("Here is the standard output of the command:\n");
while ((s = stdInput.readLine()) != null) {
LOGGER.info(s);
}
// read any errors from the attempted command
LOGGER.info("Here is the standard error of the command (if any):\n");
while ((s = stdError.readLine()) != null) {
LOGGER.info(s);
}
}
The problem is that BufferedReader.readLine() blocks until a full line (terminated by any line end char sequences) can be read, and you don't read the 2 outputs of the process "parallel", one if its buffer gets filled and the process gets blocked.
You need to read the data outputted by the process.
A process has 2 output streams: standard output and error output. You have to read both because the process might write to both of those outputs.
The output streams of the process have buffers. If the buffer of an output stream is filled, attempt to write further data to that by the process is blocked.
Do something like this:
BufferedReader stdInput = new BufferedReader(
new InputStreamReader(p.getInputStream()));
BufferedReader stdError = new BufferedReader(
new InputStreamReader(p.getErrorStream()));
while (p.isAlive()) {
while (stdInput.ready())
LOGGER.info(stdInput.readLine());
while (stdError.ready())
LOGGER.info(stdError.readLine());
Thread.sleep(1);
}
Problem with this solution (and fixing it):
This solution has an error. The process might not write full lines to its output. If that is the case, the process might still hang for example if it writes 1 character to its standard output then stdInput.readLine() would block (because it reads until a new line character is encountered) and if the process would keep writing to its error stream, when the buffer of the error stream is full, the process would be blocked.
So it would be better not to read the output streams of the buffer by lines but by characters (of course this makes logging it harder):
StringBuilder lineOut = new StringBuilder(); // std out buffer
StringBuilder lineErr = new StringBuilder(); // std err buffer
while (p.isAlive()) {
while (stdInput.ready()) {
// Append the character to a buffer or log if it is the line end
char c = (char) stdInput.read();
if (c == '\n') { // On UNIX systems line separator is one char: '\n'
LOGGER.info(lineOut.toString());
lineOut.setLength(0);
}
else
lineOut.append(c);
}
while (stdError.ready()) {
// Append the character to a buffer or log if it is the line end
char c = (char) stdError.read()
if (c == '\n') { // On UNIX systems line separator is one char: '\n'
LOGGER.info(lineErr.toString());
lineErr.setLength(0);
}
else
lineErr.append(c);
}
Thread.sleep(1);
}
Alternative (cleaner, more simple) solution
Alternatively you could start 2 threads, one to read the standard output of the process and one to read the standard error of the process. This could simplfy things:
private static void consumeStream(final InputStream is) {
new Thread() {
#Override
public void run() {
BufferedReader r = new BufferedReader(new InputStreamReader(is));
String line;
while ((line = r.readLine()) != null)
LOGGER.info(line);
}
}.start();
}
And using it:
consumeStream(p.getInputStream());
consumeStream(p.getErrorStream());
I'm trying to use the Java Runtime.getRuntime().exec(String) command to run Festival, then use OutputStreamWriter to write some commands to the outpustream of the process.
This works great, and I'm able to do something like this:
Process p = Runtime.getRuntime().exec("festival");
Writer w = new OutputStreamWriter(p.getOutputStream());
w.append("(SayText \"Hello World\")");
w.flush();
Obviously the way I can tell this works is that it speaks the text through the speakers.
What I am having a real hard time doing is getting the text output from what I would see in the terminal. I'm trying to run some other commands (such as (voice.list)) which output text, presumably to stdout.
For example, I've tried using a BufferedReader in the following way:
BufferedReader reader = new BufferedReader (new InputStreamReader(p.getInputStream()));
w.append("(voice.list)");
w.flush();
String output = "";
String line = reader.readLine();
System.out.println(line);
while ((line = reader.readLine()) != null)
{
System.out.println("Reading: " + line);
output += line;
}
(The System.out.println's is just for debugging, I would do the entire thing in a cleaner way if I was able to get it to work.)
No matter what code I try, I'm never able to get any output from Festival. I can get output from other commands. E.G. I have tried this code as well http://en.allexperts.com/q/Java-1046/2008/2/Runtime-getRuntime-exec-cmd.htm and it works with many other commands (like ls) but not Festival.
Does anything have any idea how I would be able to get this to work?
Thanks.
Festival may output it's text on stderr instead of stdout. Try replacing
p.getInputStream()
with
p.getErrorStream()
In one commend , I'm trying to send data to System.out like this:
And in another command I'm trying to get this data from System.in.
It's strange because, it works once of many tries. I can try to run it 10 times and it's still inReader.ready() == false, and when I run it for example 11th time , it works.
Why ? How can I fix this? How to make it work everytime ?
Thanks, in advance !
You can't read your InputStream that way, since the data may not have been arrived at the second process yet. You can either read character by character, with something like:
InputStreamReader inReader = new InputStreamReader(System.in);
int data = inReader.read();
while (data != -1){
...
data = inReader.read();
}
or simple read the input line by line, using:
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
while ((String line = br.readLine()) != null) {
...
}
If your objective is to execute a shell command, don't use System.out but Runtime.getRuntime().exec(cmd) instead. Check out this question for more details.