0

In my program I have a SwingWorker starting a background process. The background process's error stream is redirected to stdout, and the stdout stream is written out (line by line) to a JTextArea. I thought I was consuming the stdout stream with this

BufferedReader processOut = new BufferedReader(
    new InputStreamReader(p.getInputStream()));

And with this inside the SwingWorker's doInBackground:

String line;
while((line = processOut.readLine()) != null)
    process(line);

On my machine, the process executes to completion and the Text Area is periodically updated. The process freezes in the background on other computers though. I've increased the size of the default command window, so that might be why I can't get any process to freeze on my computer (that is probably very wrong from the more that I read).

I tried redirecting the output inside the ProcessBuilder command with > log.txt (I'm on Windows 7 currently) but I think that's causing the p.getInputStream() call to crash.

How can I either consume the stdout of the subprocess properly inside my SwingWorker class, or is it possible to pipe the output to a file and still get the output to print to the JTextArea.

Edit:

I read here That an input stream needs to be read promptly to be consumed. I've provided the loop that processes the input stream below. I would assume that the pipe doesn't get more than 4K of data before it is read, but I can't assume anything at this point.

    while(processIsAlive())
    { 
        if(isCancelled())
        {
            try
            {
                p.destroy();
                p.waitFor();
                return 1;
            }
            catch(Exception e){}
        }

        try
        {
            //Update Text Area

            //get output from process
            while((line = processOut.readLine()) != null)
            {
                //print output to text area
                publish(line);
            }

            sleep(1000);
        }
        catch(Exception e){}
    }

EDIT 2:

I thought that having the process redirected to a file, then putting an InputStream on that same file would be impossible, but its not crashing my program and the GUI is still updated properly. I'm going to go test this on the problematic machine, then I'm going to mark it as an answer if it works.

All I did was redirect the process to a file:

pb.redirectOutput(new File("log.txt"));

And put the InputStream on that file instead of the process stdout stream.

processOut = new BufferedReader(new FileReader("log.txt"));
Community
  • 1
  • 1
Cullen S
  • 155
  • 1
  • 3
  • 10

2 Answers2

0

When starting processes, it's convenient to read the stdout and stderr in a separate thread each one, because reading must be done through a call to InputStream.read(), which does block the owner thread.

You said that your background process was redirecting errors to stdout, ok. Then, read only the stdout, but do it always in a separate thread, because the main thread gets blocked in the waitFor call until the process ends. But the process will block if its output buffer gets full and nobody is reading it.

In this case, the difference between your local environment (success) and the others (failing) could be that, in yours, the amount of data fits in the output buffer.

Little Santi
  • 8,563
  • 2
  • 18
  • 46
0

My second edit will work on any machine with Java 7 or later. The reading from the input stream is blocking, so that is incorrect for using in a GUI but the process streams are read from appropriately.

The actual problem with the machine was that for some reason the program wasn't flushing appropriately, so I added fflush(stdout) to the c source code in the problematic program, and it worked perfectly.

Cullen S
  • 155
  • 1
  • 3
  • 10