I am running into some problems using ProcessBuilder, Process, and BufferedReaders in my Java program. For some inputs, the function runs perfectly but with others the BufferedReader reads nothing and returns empty strings. I am not sure what may be causing this bug.
I have tried debugging and for those situations where nothing is being read, the BufferedReader is completely skipping the loop. For example, when I pass in the command as 'ipconfig', which has >50 lines of CMD output, it returns every line exactly as displayed. But when I pass in the command as 'java -version', it completely skips the output (there are 3 lines that should be read).
ProcessBuilder/Reading function:
public static String runCommandToStdOut(String command) throws InterruptedException, IOException {
StringBuilder sBuilder = new StringBuilder();
pBuilder = new ProcessBuilder();
String[] processArray = command.split(" ");
pBuilder.command(processArray);
process = pBuilder.start();
process.waitFor();
BufferedReader bReader = new BufferedReader(new InputStreamReader(process.getInputStream()));
//reading cmd output to string
String line = "";
while ((line = bReader.readLine()) != null) {
sBuilder.append(line);
sBuilder.append(System.getProperty("line.separator"));
}
return sBuilder.toString();
}
How I am calling the function:
try {
String stdOut = osCommandService.runCommandToStdOut("java -version");
}
The stdOut string in the second code section is empty. That means the line 'sBuilder.toString' is an empty string after the function is run. The output that I see when I run 'java -version' directly in my cmd prompt is 3 lines long, which evidently isn't being read properly.
Related
I want to run a command line programme on Windows, here is the code.
public static String runcmd(String cmd) throws IOException {
ProcessBuilder builder = new ProcessBuilder(cmd);
builder.redirectErrorStream(true);
Process p = builder.start();
BufferedReader r = new BufferedReader(new InputStreamReader(p.getInputStream()));
String line;
StringBuilder sb = new StringBuilder();
while (true) {
line = r.readLine();
if (line == null)
break;
sb.append(line + "%SKIPLINE%");
}
System.out.println(sb.toString());
return sb.toString();
}
Everything work fine, except that it prints out the output in Chinese because my Windows language is set to Chinese. Is there any ways to make it output in English?
Check this link: how to detect operating system language (locale) from java code
What you want to find is a way to temporarily set your locale in the program to English.
Try this:
https://wandersick.blogspot.com/p/change-non-english-command-line.html
Or
Execute
chcp 437
in the cmd prompt.
For example:
C:\Users\javaserv> chcp 437
Active code page: 437
Hope it helps!
Just found this post (and found the code which I'm also pasting below):
java runtime.getruntime() getting output from executing a command line program
My question is, how do I kill the process? It seems that the code blocks in the while loop. I've tried several options like using a boolean, running all the code in a separate thread and stuff like this, but without any success.
I just want to start an Android emulator and kill it whenever I want.
Runtime rt = Runtime.getRuntime();
String[] commands = {"emulator", "-avd", "jenkins",
"-scale", "96dpi", "-dpi-device", "100"};
Process proc = rt.exec(commands);
BufferedReader stdInput = new BufferedReader(new
InputStreamReader(proc.getInputStream()));
BufferedReader stdError = new BufferedReader(new
InputStreamReader(proc.getErrorStream()));
// read the output from the command
System.out.println("Here is the standard output of the command:\n");
String s = null;
while ((s = stdInput.readLine()) != null) {
System.out.println(s);
}
// read any errors from the attempted command
System.out.println("Here is the standard error of the command (if any):\n");
while ((s = stdError.readLine()) != null) {
System.out.println(s);
}
Okay.
Use below code to get The Process ID of that current running thread or Process.
String processName =java.lang.management.ManagementFactory.getRuntimeMXBean().getName();
String ProcessID = processName.split("#")[0];//Process Id
Use that Process ID to kill that Process in your CPU.
I think for that purpose you may wish to write any other trigger or any condition in While loop.
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());
For some terminal commands, they repeatedly output. For example, for something that's generating a file, it may output the percent that it is complete.
I know how to call terminal commands in Java using
Process p = Runtime.getRuntim().exec("command goes here");
but that doesn't give me a live feed of the current output of the command. How can I do this so that I can do a System.out.println() every 100 milliseconds, for example, to see what the most recent output of the process was.
You need to read InputStream from the process, here is an example:
Edit I modified the code as suggested here to receive the errStream with the stdInput
ProcessBuilder builder = new ProcessBuilder("command goes here");
builder.redirectErrorStream(true);
Process process = builder.start();
InputStream is = process.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
String line = null;
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
For debugging purpose, you can read the input as bytes instead of using readLine just in case that the process does not terminate messages with newLine
I want to count the lines of file using java and the code that i use is:
String[] wcCommand = new String[]{"/usr/bin/wc","-l" , filePath};
Process wcProcess=Runtime.getRuntime().exec(wcCommand);
wcProcess.waitFor();
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader( wcProcess.getInputStream()));
String numberOfRowsline;
while((numberOfRowsline = bufferedReader.readLine()) != null) {
System.out.print(numberOfRowsline);
}
If i have large file with 5000000 rows then the command returns wrong number. Why this happens? When i execute the command direct from the terminal the returned value is correct.
The output from java is: 3288079 /PathToFile
The output from terminal: 5000000 /PathToFile