简体   繁体   中英

Get the output result of a process with java

I want to execute a process for some time and then get the output and destroy the process. This is my code

BufferedReader stdInput = new BufferedReader(new InputStreamReader(p.getInputStream()));
BufferedReader temp;
p.waitFor(7, TimeUnit.SECONDS);
temp=stdInput;
p.destroy(); 
System.out.println(temp.readLine());

but I get as result

java.io.IOException: Stream closed

How can I copy the result after executing the process 7 seconds? If I use this code

p.waitFor(7, TimeUnit.SECONDS);
while ((inputRead=stdInput.readLine()) != null){
    Helper.log(inputRead);
}

the while loop will never terminate because the process is still alive after the waitFor , so I have to destroy it. And If I destroy the process I am not able to get the content of stdInput anymore.

You don't want that call to waitFor() since it waits until the process is destroyed. You also don't want to read for as long as the InpuutStream is open, since such a read would terminate only when the process is killed.

Instead, you can simply start the process, and then wait for 7 seconds. Once 7 seconds have passed, read the available data in the buffer without waiting for the stream to close:

BufferedReader stdInput = new BufferedReader(new InputStreamReader(p.getInputStream()));
Thread.sleep(7000); //Sleep for 7 seconds
while (stdInput.ready()) { //While there's something in the buffer
     //read&print - replace with a buffered read (into an array) if the output doesn't contain CR/LF
    System.out.println(stdInput.readLine()); 
}
p.destroy(); //The buffer is now empty, kill the process.

If the process keeps printing, so stdInput.ready() always returns true you can try something like this:

BufferedReader stdInput = new BufferedReader(new InputStreamReader(p.getInputStream()));
char[] buffer = new char[16 * 1024]; // 16 KiB buffer, change size if needed
long startedReadingAt = System.currentTimeMillis(); //When did we start reading?
while (System.currentTimeMillis() - startedReadingAt < 7000) { //While we're waiting
    if (stdInput.ready()){
        int charsRead = stdInput.read(buffer); //read into the buffer - don't use readLine() so we don't wait for a CR/LF
        System.out.println(new String(buffer, 0, charsRead));  //print the content we've read
    } else {
        Thread.sleep(100); // Wait for a while before we try again
    }
}
p.destroy(); //Kill the process

In this solution, instead of sleeping, the thread spends the next 7 seconds reading from the InputStream , then it closes the process.

java.io.IOException: Stream closed That is probably because you're calling temp.readLine() after p.destroy() .

The problem seems to be that the process doesn't add a new line termination after the part that you want to retrieve. To fix that, you can read the output from the program in small chunks instead of line by line.

Here is an example:

try(InputStream is = p.getInputStream()){
    byte[] buffer = new byte[10];
    String content = "";
    for(int r = 0; (r = is.read(buffer))!=-1;){
        content+=new String(buffer, 0, r);
        if(content.equals("all content")){// check if all the necessary data was retrieved.
            p.destroy();
            break;
        }
    }
}catch(Exception e){
    e.printStackTrace();
}

If you know the exact format of the program's output, a better solution will be to use a scanner.

try(Scanner sc = new Scanner(p.getInputStream())){
    while(sc.hasNext()){
        String word = sc.next();
    }
}catch(Exception e){
    e.printStackTrace();
}

The example above will read the program's output one word at a time.

From your comments it seems that the problem is that the process never terminates by itself and your program never exits the while loop.

To fix that, you can use a timer to destroy the process after a period of time, here is an example:

Timer t = new Timer();
t.schedule(new TimerTask() {
    @Override
    public void run() {
        p.destroy();
        t.cancel();
        t.purge();
    }
}, 7000);

try(BufferedReader stdInput = new BufferedReader(new InputStreamReader(p.getInputStream()));){
    while ((inputRead=stdInput.readLine()) != null){
        ...
    }
}catch(Exception e){
    e.printStackTrace();
}

Keep in mind that this approach will always cause stdInput.readLine() to throw an exception.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM