有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

processbuilder使用java获取进程的输出结果

我想执行一个进程一段时间,然后得到输出并销毁该进程。这是我的密码

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

但我得到的结果是

java.io.IOException: Stream closed

如何在执行流程7秒后复制结果?如果我使用这个代码

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

while循环永远不会终止,因为进程在waitFor之后仍然处于活动状态,所以我必须销毁它。如果我破坏了进程,我就无法再获得stdInput的内容


共 (2) 个答案

  1. # 1 楼答案

    java.io.IOException: Stream closed这可能是因为您在p.destroy()之后调用temp.readLine()

    问题似乎是,该过程没有在要检索的零件后添加新行终止符。要解决这个问题,可以将程序的输出分成小块,而不是逐行读取

    下面是一个例子:

    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();
    }
    

    如果您知道程序输出的确切格式,更好的解决方案是使用扫描仪

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

    上面的例子将一次读取一个单词的程序输出

    从您的评论来看,问题似乎在于进程永远不会自行终止,并且您的程序永远不会退出while循环

    要解决这个问题,可以使用计时器在一段时间后销毁进程,下面是一个示例:

    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();
    }
    

    请记住,这种方法总是会导致stdInput.readLine()抛出异常

  2. # 2 楼答案

    您不希望调用waitFor(),因为它会等待进程被销毁。只要InpuutStream处于打开状态,您也不希望读取,因为这样的读取只有在进程终止时才会终止

    相反,你可以简单地启动这个过程,然后等待7秒钟。7秒后,在不等待流关闭的情况下读取缓冲区中的可用数据:

    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.
    

    如果进程一直在打印,那么stdInput.ready()总是返回true,您可以尝试以下方法:

    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
    

    在这个解决方案中,线程不再休眠,而是在接下来的7秒钟内读取InputStream,然后关闭进程