【问题标题】:reading output of a child process Interruptibly中断地读取子进程的输出
【发布时间】:2014-05-16 13:24:00
【问题描述】:

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

我的第一次尝试是在另一个线程中调用InputStream.close(),但是虽然它适用于套接字,但它不适用于Process.getInputStream()的结果:主线程仍在等待read()和杀手线程要么挂在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
        }
    }
}

我最后的希望是从返回的流中窃取频道并使用 nio

【问题讨论】:

  • 您想读取其他进程写入流中的内容还是要杀死该进程
  • @Mani srsly,“我想启动一个子进程并读取它的输出”
  • 那么为什么要试图杀死/关闭流。并且您正在执行的命令不会自行终止(更多和更多)
  • @Mani 这只是一个例子。我不介意它是否被杀死,但主要目标是退出 read()
  • 请看我的回答。如果您想阅读,可以使用它来阅读。

标签: java process pipe


【解决方案1】:

在 windows 中,此命令不会终止。

 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 中为 Process 创建 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();
        }


    }
}

看看这个示例:你应该有一些条件来终止子线程(读取进程),比如流写入“end”/或 EOF 结束(进程关闭输入流)

【讨论】:

  • "在 windows 中,此命令不会终止。" - 这才是重点!我无法接受您的回答,因为它无法停止从无法终止的进程中读取
  • 你的意思。您需要有条件停止( EOF - 在您的情况下它不是 EOF )或基于输出
  • 查看我的最后一条笔记。如果您对等到 EOF 不感兴趣,那么您必须设置条件。就像流写入结束/退出/终止一样,你应该销毁
  • destroy 不会杀死整棵树,因此不会关闭它们的末端
猜你喜欢
  • 1970-01-01
  • 2016-03-14
  • 1970-01-01
  • 2012-06-07
  • 1970-01-01
  • 2012-04-06
  • 2016-04-09
  • 1970-01-01
相关资源
最近更新 更多