java-在写入缓冲区时从进程读取

时间:2013-08-06 11:22:15

标签: java

我有一个程序,我在其中调用另一个单独的程序来完成一些工作(让我们称之为子流程),子流程需要一些时间来完成每个任务并在简单的控制台中显示进度。

问题是,当我尝试使用BufferedReader读取该控制台时,我自己的程序在写入TextArea中的每一行之前等待子进程完成。

这是我用来阅读每一行的代码:

    JTextArea report = new JTextArea(20,40);
    report.setText("");
    try
            {
                Process p = new ProcessBuilder(command).start();
                p.waitFor();
                BufferedReader reader=new BufferedReader(new  InputStreamReader(p.getInputStream()));
                String line = reader.readLine();
                while(line!=null) 
                { 
                report.append(line+"\n");
                line=reader.readLine(); 
                }
            }
            catch(IOException e1){ error.setText("Failed to run toxpack");}
            catch(InterruptedException e2) {error.setText("Failed to run command");}

我试图查看线程,但它仍然无效。

如何阅读每一行并将其添加到textArea中,而无需等待整个子流程完成。

编辑:添加了其余的代码,但我不确定它是否有用。 我想说的是,我希望子流程输出的每一行都出现在我的textArea中。没有等待它完成。

2 个答案:

答案 0 :(得分:0)

您应该创建另一个从该进程读取的线程,并更新Swing组件:

    final Process p = new ProcessBuilder("cat", "/etc/hosts").start();
    final BufferedReader br = new BufferedReader(new InputStreamReader(
            p.getInputStream()));

    final Runnable r = new Runnable() {
        @Override
        public void run() {
            try {
                try {
                    for (String line = br.readLine(); line != null; line = br
                            .readLine()) {
                        final String l = line;
                        System.out.println(l);
                        EventQueue.invokeLater(new Runnable() {
                            @Override
                            public void run() {
                                textArea.setText(textArea.getText() + "\n" + l);
                            }
                        });

                        Thread.sleep(50);
                    }
                } finally {
                    br.close();
                }
            } catch (Exception ex) {
                ex.printStackTrace();
            }
        }
    };

    final Thread t = new Thread(r);
    t.start();

现在在阅读器线程中连续读取行,并且使用EventQueue.invokeLater将Swing的更新发布到Swing的事件队列中,因为在Swing的事件调度线程中没有完成读取(详情:{{3} })。

sleep只是为了减慢速度(模拟缓慢流动的数据)。

一起
public class TextAreaDemo {

public static void main(String[] args) {
    final JTextArea textArea = new JTextArea(60, 5);

    final JScrollPane sp = new JScrollPane(textArea,
            JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
            JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS) {
        @Override
        public Dimension getPreferredSize() {
            return new Dimension(600, 300);
        }

    };

    final JFrame frame = new JFrame();
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.getContentPane().add(sp);
    frame.pack();
    frame.setVisible(true);

    // Add the reader snippet here
}

}

它将更新文本区域中的值。

答案 1 :(得分:-1)

这里有两个可能的问题:

1)如果其他进程没有写入整行,那么显然没有可以从输入流中读取的行。在这种情况下,readLine方法会等到它有一个整行(在该过程完成后可能为真)。

2)更有可能:另一个进程写入缓冲写入器,但不刷新其内容。这导致在流程结束时刷新buffere。如果其他进程是Java进程,那么使用PrintWriter将是最佳选择。 PrintWriter应该以这种方式构建:

PrintWriter writer = new PrintWriter(..., true)

true参数启用此打印编写器的自动刷新行为。请参阅PrintWriter文档。

修改

我刚看到p.waitFor()电话。这会导致您的线程真正等到另一个进程完成。只需删除该行。