Java 可中断地读取子进程的输出

Java 可中断地读取子进程的输出,java,process,pipe,Java,Process,Pipe,我想启动一个子进程并读取其输出,直到EOF或清除内部标志 我的第一次尝试是在另一个线程中调用InputStream.close(),但尽管它对套接字有效,但它对进程的结果不起作用。getInputStream():主线程仍在read()中等待,而killer线程要么挂起在close0()(windows)中,要么继续无效(linux) 然后我尝试检查InputStream.available(),但它没有检测到EOF:它返回0 public class BbbTest extends TestC

我想启动一个子进程并读取其输出,直到EOF或清除内部标志

我的第一次尝试是在另一个线程中调用
InputStream.close()
,但尽管它对套接字有效,但它对
进程的结果不起作用。getInputStream()
:主线程仍在
read()
中等待,而killer线程要么挂起在
close0()
(windows)中,要么继续无效(linux)

然后我尝试检查
InputStream.available()
,但它没有检测到EOF:它返回0

public class BbbTest extends TestCase {

    private Process proc;
    private InputStream getStream() throws IOException {

        //if ("".length() == 0) return new java.net.Socket("intra", 80).getInputStream();

        String[] cmd;
        if (System.getProperty("os.name").toLowerCase().startsWith("windows")) {
            cmd = new String[] { "cmd", "/c", "more & more" };
        } else {
            cmd = new String[] { "sh", "-c", "cat; cat" };
        }
        Process proc = Runtime.getRuntime().exec(cmd);
        return proc.getInputStream();
    }

    public void testB() throws Exception {
        final InputStream in = getStream();
        final Thread readingThread = Thread.currentThread();
        Thread t = new Thread("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx") {
            @Override
            public void run() {
                try {
                    sleep(1000);
                    if (proc != null) proc.destroy(); // this won't help
                    readingThread.interrupt(); // this won't help either
                    in.close(); // this will do nothing and may even hang
                } catch (RuntimeException e) {
                    throw e;
                } catch (Exception e) {
                    throw new RuntimeException ( );
                }
            }
        };
        t.setDaemon(true);
        t.start();

        try {
            in.read();
            assertTrue(false);
        } catch (IOException e) {
            // nothing
        }
    }
}

我最后的希望是从返回的流中窃取通道并在windows中使用nio,此命令不会终止

 cmd = new String[] { "cmd", "/c", "more & more" };
不要尝试这个简单的命令

 cmd = new String[] { "cmd", "/c", "dir" };
如果你想读你的流

public static void slurp(final InputStream is, final int bufferSize)
    {
        try(final Reader in = new InputStreamReader(is, "UTF-8");
                BufferedReader br = new BufferedReader(in);){
            String line;
            while ((line = br.readLine()) != null) {
                System.out.println(line);
            }
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
通过像这样传递流来调用此方法

final BbbTest bbTest = new BbbTest();
    Thread t = new Thread("xsdfds") {
                @Override
                public void run() {
                    try {
                        slurp(bbTest.getStream());
                    } catch (RuntimeException e) {
                        throw e;
                    } catch (Exception e) {
                        throw new RuntimeException ( );
                    }
                }
            };
            t.start();
如果要从子线程终止进程。 在BbbTest中为流程创建setter和getter方法,如下所示

public class BbbTest {

    private Process proc;

    /**
     * @return the proc
     */
    public Process getProc() {
        return proc;
    }

    /**
     * @param proc the proc to set
     */
    public void setProc(Process proc) {
        this.proc = proc;
    }
        private InputStream getStream() throws IOException {
        String[] cmd;
        if (System.getProperty("os.name").toLowerCase().startsWith("windows")) {
            //  cmd = new String[] { "cmd", "/c", "more & more" };
            cmd = new String[] { "cmd", "/c", "dir" };
        } else {
            cmd = new String[] { "sh", "-c", "cat; cat" };
        }
        proc = Runtime.getRuntime().exec(cmd);
        return proc.getInputStream();
    }
}
现在,使用这个过程,您可以销毁

bbTest.getProc().destroy();
如果希望基于其他流的输出终止进程,可以通过检查行内容在slurp方法中添加逻辑,并使用destroy终止

UPDATE
简单演示

public class BbbTest {


    private Process startProcess(String[] commands) throws IOException {
        Process proc = Runtime.getRuntime().exec(commands);
        return proc;
    }

    public static void slurp(final InputStream is)
    {
        try(final Reader in = new InputStreamReader(is, "UTF-8");
                BufferedReader br = new BufferedReader(in);){
            String line;
            while ((line = br.readLine()) != null) {
                System.out.println(line);
                if (line.equals("end")){
                    break;
                }
            }
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static void main(String args[]) throws Exception {
        final BbbTest bbTest = new BbbTest();
        final Process process = bbTest.startProcess(new String[] { "cmd", "/c", "more" });
        Thread t = new Thread("xsdfds") {
            @Override
            public void run() {
                try {
                    slurp(process.getInputStream());
                    process.destroy();
                } catch (RuntimeException e) {
                    throw e;
                } catch (Exception e) {
                    throw new RuntimeException ( );
                }
            }
        };
        t.start();

        try(OutputStream out = process.getOutputStream();
                BufferedOutputStream outStream = new BufferedOutputStream(out);){
            outStream.write("Test".getBytes());
            outStream.write("\n".getBytes());
            outStream.write("end".getBytes());
            outStream.write("\n".getBytes());
            outStream.flush();
        }


    }
}

看看这个示例:您应该有一些条件来终止子线程(读取prcoess),比如流写入“end/”或EOF的end(process closed inputstream)

您想要读取另一个进程在流中写入的内容,还是想要终止子线程process@Mani不幸的是,“我想启动一个子进程并读取其输出”那么为什么要尝试终止/关闭该流。并且您正在执行的命令不会自行终止它(more&more)@Mani这只是一个示例。我不介意它是否被终止,但主要目标是退出read(),请查看我的答案。如果您想读取,可以使用该命令进行读取。”在windows中,此命令不会终止。“-这就是问题所在!我不能接受您的答案,因为它无法停止从无法终止的进程中读取您的意思。您需要有条件停止(EOF-在您的情况下,它不是EOF)或者基于outputCheck我的最后一个注释。如果您不想等到EOF,那么您必须进行条件设置。例如,如果流写入结束/退出/终止,您应该销毁它不会杀死整个树,因此不会关闭它们的管道末端