Вопрос

I start a cmd application that outputs to System.out through this SyncPipe Runnable:

public class SyncPipe implements Runnable {

    private final InputStream is;
    private final OutputStream os;

    public SyncPipe(InputStream is, OutputStream os) {
        this.is = is;
        this.os = os;
    }

    public void run() {
        try {
            final byte[] buffer = new byte[1024];
            for ( int length = 0; ( length = is.read(buffer) ) != -1; )
                os.write(buffer, 0, length);
            System.out.print("stopped");
        } catch ( Exception ex ) { 
            ex.printStackTrace(); 
        }
    }

}

I start RunIt with cmd = "C:/bin/read.exe -f D:/test.jpg"

private class RunIt implements Runnable {

    public int p;
    public String cmd;

    public RunIt (int p, String cmd) {
        this.p = p;
        this.cmd = cmd;
    }

    public void run() {
        ProcessBuilder pb = new ProcessBuilder("cmd");
        try {
            process = pb.start();
            (new Thread(new SyncPipe(process.getErrorStream(), System.err))).start();
            (new Thread(new SyncPipe(process.getInputStream(), System.out))).start();
            OutputStream out = process.getOutputStream();
            out.write((cmd + "\r\n").getBytes());
            out.flush();
            out.close();

            try {
                process.waitFor();
            } catch ( InterruptedException e ) {
                e.printStackTrace();
            }

            println("Stopped using %d.", p);
        } catch ( IOException ex ) {
            ex.printStackTrace();
        }
    }

}

My question now: How can I make (new Thread(new SyncPipe(process.getErrorStream(), System.err))) die? Giving SyncPipe a boolean variable stop, setting it true during runtime, and checking for it via for ( int length = 0; ( length = is.read(buffer) ) != -1 && !stop; ) did not do the trick.

Thanks a lot in advance.


I ended up doing the work-around that @Gray suggested. It works now:

public void run() {
    try {
        final byte[] buffer = new byte[1024];
        do
            if ( is.available() > 0 ) {
                int length = is.read(buffer);
                if ( length != -1 )
                    os.write(buffer, 0, length);
                else
                    stop = true;
            }
        while ( !stop );
    } catch ( Exception ex ) { 
        ex.printStackTrace(); 
    }
}
Это было полезно?

Решение

The thread will read EOS and exit when the underlying process exits. You don't have to do anything special about it yourself.

EDIT It seems to me from reading your comments to other answers that your real problem is ending the process. These threads will come unstuck as soon as that happens. You're attacking the wrong end of the problem.

Другие советы

InputStream#read() states

This method blocks until input data is available, the end of the stream is detected, or an exception is thrown.

So when you go into your for loop

for ( int length = 0; ( length = is.read(buffer) ) != -1; )
    os.write(buffer, 0, length);

it won't be able to exit until the end of the stream is reached, ie. the process stops or you close the streams yourself.

If the whole point of the SyncPipe is to pass the content to your standard output/error streams, why would you want to stop the Thread running it?

My question now: How can I make (new Thread(new SyncPipe(process.getErrorStream(), System.err))) die?

You are going to have to close the input stream out from under it I believe. I suspect that it is blocked in the read and no setting of a stop variable (even if properly volatile) will get the read thread to unblock.

You are going to need to do something like:

 InputStream is = process.getInputStream();
 InputStream es = process.getErrorStream();
 ...
 is.close();
 es.close();

Code would look approximately like the following. I'm not sure if your waitFor() call is returning or not.

 InputStream is = process.getInputStream();
 InputStream es = process.getErrorStream();
 (new Thread(new SyncPipe(es, System.err))).start();
 (new Thread(new SyncPipe(is, System.out))).start();
 try {
     OutputStream out = process.getOutputStream();
     out.write((cmd + "\r\n").getBytes());
     out.flush();
     out.close();
     try {
         process.waitFor();
     } catch ( InterruptedException e ) {
         e.printStackTrace();
     }
 } finally {
     is.close();
     es.close();
 }

Another answer might be to use the available() method on InputStream so you can loop and check your stop flag. See this answer: https://stackoverflow.com/a/1089079/179850

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top