It seems that using BufferedReader to read a process's InputStream
will somehow result in a block I/O behavior.
And the effect is like the program doesn't get the instant input from the process.
I know there are more lines that could be read at that time, but the BufferedReader
just keep waiting for sometime then I can finally get the lines updated.
Here is the code:
While((str=bufferedReader.readLine()!=null) {
System.out.println(str);
}
Is there some kinds of method that can keep reading from the process without blocking
in the while() condition? cause the process won't return null or anything....
You can read the child process output in a separate thread. Something like this
static BlockingQueue<String> queue = new LinkedBlockingDeque<>();
public static void main(String[] args) throws Exception {
Process p = Runtime.getRuntime().exec("cmd /c dir");
final BufferedReader rdr = new BufferedReader(new InputStreamReader(p.getInputStream()));
Thread t = new Thread() {
public void run() {
try {
for (String line; (line = rdr.readLine()) != null;) {
queue.put(line);
}
} catch (Exception e) {
e.printStackTrace();
}
}
};
t.start();
for (;;) {
String line = queue.poll();
if (line != null) {
System.out.println(line);
} else if (!t.isAlive()) {
break;
}
}
}
You can use the NuProcess library for non-blocking I/O to external processes. Consider it a replacement for ProcessBuilder and Process in Java.
Related
I try to download folders from Google storage on the cloud.
I run from a process of a user that have permissions (when i run from regular terminal on mac it works)
I have this code:
public void runCommand() {
final Process p;
try {
p = Runtime.getRuntime().exec(
"gsutil -m cp -r gs://my_bucket/705/201609040613/output/html_pages file:/Users/eladb/WorkspaceQa/GsClient/build/resources/main/downloads/");
new Thread(new Runnable() {
public void run() {
BufferedReader input = new BufferedReader(new InputStreamReader(p.getInputStream()));
String line = null;
try {
while ((line = input.readLine()) != null)
System.out.println(line);
} catch (IOException e) {
e.printStackTrace();
}
}
}).start();
p.waitFor();
} catch (Exception e) {
e.printStackTrace();
}
}
but the new thread never returns.
stuck on line:
while ((line = input.readLine()) != null)
Is there any way to download these folders from google cloud otherwise?
This manual copying of stdout data is error prone (you would have to forcefully close the stream to terminate the sub thread) and thankfully, unnecessary since Java 7:
public void runCommand() {
try {
new ProcessBuilder("gsutil", "-m", "cp", "-r",
"gs://my_bucket/705/201609040613/output/html_pages",
"file:/Users/eladb/WorkspaceQa/GsClient/build/resources/main/downloads/")
.inheritIO()
.start()
.waitFor();
} catch(IOException | InterruptedException e) {
e.printStackTrace();
}
}
If you don’t want to direct all three channels this way, see redirectOutput(File), redirectOutput(ProcessBuilder.Redirect), and the similar methods for input and error channel.
Only the (default) mode ProcessBuilder.Redirect.PIPE requires you to provide input or receive output while the sub-process is runnig.
I was trying to get the logcat content into a JTextPane. I used following code hoping it will return the content as String but it freeze and also, doesn't produce an error.
Process exec = null;
try {
exec = Runtime.getRuntime().exec("adb logcat -d");
InputStream errorStream = exec.getErrorStream();
BufferedReader ebr = new BufferedReader(new InputStreamReader(errorStream));
String errorLine;
while ((errorLine = ebr.readLine()) != null) {
System.out.println("[ERROR] :- " + errorLine);
}
if (exec.waitFor() == 0) {
InputStream infoStream = exec.getInputStream();
InputStreamReader isr = new InputStreamReader(infoStream);
BufferedReader ibr = new BufferedReader(isr);
String infoLine;
while ((infoLine = ibr.readLine()) != null) {
System.out.println("[INFO] :- " + infoLine);
}
}
} catch (IOException | InterruptedException ex) {
ex.printStackTrace();
} finally {
if (exec != null) {
exec.destroy();
}
}
I referred to some tutorials but, they were not filling my problem. Is this wrong? Are there any other methods to get the logcat content as a String programmatically? Sorry if this is a dumb question.
The issue you're seeing is that you're trying to process command streams and wait for the executing process, all in the same thread. It's blocking because the process reading the streams is waiting on the process and you're losing the stream input.
What you'll want to do is implement the function that reads/processes the command output (input stream) in another thread and kick off that thread when you start the process.
Second, you'll probably want to use ProcessBuilder rather than Runtime.exec.
Something like this can be adapted to do what you want:
public class Test {
public static void main(String[] args) throws Exception {
String startDir = System.getProperty("user.dir"); // start in current dir (change if needed)
ProcessBuilder pb = new ProcessBuilder("adb","logcat","-d");
pb.directory(new File(startDir)); // start directory
pb.redirectErrorStream(true); // redirect the error stream to stdout
Process p = pb.start(); // start the process
// start a new thread to handle the stream input
new Thread(new ProcessTestRunnable(p)).start();
p.waitFor(); // wait if needed
}
// mimics stream gobbler, but allows user to process the result
static class ProcessTestRunnable implements Runnable {
Process p;
BufferedReader br;
ProcessTestRunnable(Process p) {
this.p = p;
}
public void run() {
try {
InputStreamReader isr = new InputStreamReader(p.getInputStream());
br = new BufferedReader(isr);
String line = null;
while ((line = br.readLine()) != null)
{
// do something with the output here...
}
}
catch (IOException ex) {
ex.printStackTrace();
}
}
}
}
Here is the situation:
I have a java application which executes another java application example.exe (example.exe has some System.out.println("...");)
I want to get the output Stream from example.exe so i tried with something like that:
(looks pretty standard)
final Process process = Runtime.getRuntime().exec("example.exe");
new Thread() {
public void run() {
try {
BufferedReader inputReader = new BufferedReader(new InputStreamReader(process.getInputStream()));
String line = "";
try {
while((line = inputReader.readLine()) != null) {
inputText = inputText + line;
}
System.out.println(inputText);
} finally {
inputReader.close();
}
} catch(IOException ioe) {
ioe.printStackTrace();
}
}
}.start();
I would like to get the output messages of example.exe but it doesn't work and i don"t understand why, i get one message but not the one from example.exe, probably from java or something else.
I need to execute a command in my java program but after executing the command , it required another parameter ( a password in my case ). how can I manage the output process of Runtime.getRuntime().exec() to accept parameter for further execution ?
I tried new BufferedWriter(new OutputStreamWriter(signingProcess.getOutputStream())).write("123456"); but it did not work.
Does your program not feature a --password option ? Normally all command line based programs do, mainly for scripts.
Runtime.getRuntime().exec(new String[]{"your-program", "--password="+pwd, "some-more-options"});
Or the more complicated way and much more error-prone:
try {
final Process process = Runtime.getRuntime().exec(
new String[] { "your-program", "some-more-parameters" });
if (process != null) {
new Thread(new Runnable() {
#Override
public void run() {
try {
DataInputStream in = new DataInputStream(
process.getInputStream());
BufferedReader br = new BufferedReader(
new InputStreamReader(in));
String line;
while ((line = br.readLine()) != null) {
// handle input here ... ->
// if(line.equals("Enter Password:")) { ... }
}
in.close();
} catch (Exception e) {
// handle exception here ...
}
}
}).start();
}
process.waitFor();
if (process.exitValue() == 0) {
// process exited ...
} else {
// process failed ...
}
} catch (Exception ex) {
// handle exception
}
This sample opens a new thread (keep in mind concurrency and synchronisation) that's going to read the output of your process. Similar you can feed your process with input as long as it has not terminated:
if (process != null) {
new Thread(new Runnable() {
#Override
public void run() {
try {
DataOutputStream out = new DataOutputStream(
process.getOutputStream());
BufferedWriter bw = new BufferedWriter(
new OutputStreamWriter(out));
bw.write("feed your process with data ...");
bw.write("feed your process with data ...");
out.close();
} catch (Exception e) {
// handle exception here ...
}
}
}).start();
}
Hope this helps.
Runtime r=Runtime.getRuntime();
process p=r.exec("your string");
try this way
You should give in parameter your windows command if you work on windows
visit this link for more details : http://docs.oracle.com/javase/6/docs/api/java/lang/Runtime.html
I am trying to interact with another process in Java. It goes like this...
Runtime rt;
Process pr=rt.exec("cmd");
then I send some commands to the process using...
BufferedReader processOutput = new BufferedReader(new InputStreamReader(pr.getInputStream()));
BufferedWriter processInput = new BufferedWriter(new OutputStreamWriter(pr.getOutputStream()));
processInput.write("gdb");
processInput.flush();
I don't care about the output for now.. so I try to ignore it using..
while(processOutput.readLine() != null);
but this loops hangs forever. I know this is because process is still running and doesn't sends a null. I don't want to terminate it now. I have to send commands based on user Input and then get the output..
How to do this? In other words I want to flush the Process output stream or ignore it after executing some commands and read it only when I want to.
Use a separate thread to read the output. This way, as long as there is output it will be read, but will not block you.
For example, create such a class:
public class ReaderThread extends Thread {
private BufferedReader reader = null;
public ReaderThread(BufferedReader reader) {
this.reader = reader;
}
#Override
public void run() {
String line = null;
try {
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
}
catch(IOException exception) {
System.out.println("!!Error: " + exception.getMessage());
}
}
}
And in your main class, instead of while(processOutput.readLine() != null);, call:
ReaderThread reader = new ReaderThread(processOutput);
reader.start();