如何实时读取和写入进程,并在JTextArea中实时显示输出?(Java Swing)

如何实时读取和写入进程,并在JTextArea中实时显示输出?(Java Swing),java,multithreading,swing,io,Java,Multithreading,Swing,Io,我复制并修改了此处发布的答案代码: 我的代码的问题是,它只在代码启动时工作一次。任何后续的write调用都不会起任何作用 这是我的密码: 大型机类 public class MainFrame extends JFrame { private JTextArea Output; private JScrollPane outputScrollPane; private JButton clickMe; private ProcessThread proces

我复制并修改了此处发布的答案代码:

我的代码的问题是,它只在代码启动时工作一次。任何后续的write调用都不会起任何作用

这是我的密码:

大型机类

public class MainFrame extends JFrame {

    private JTextArea Output;
    private JScrollPane outputScrollPane;
    private JButton clickMe;

    private ProcessThread processThread;
    private ExecutorService execService;

    public MainFrame() {
        setTitle("StackOverflow");
        setSize(700, 850);
        setMinimumSize(new Dimension(650,800));
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setLayout(new BorderLayout());

        Output = new JTextArea();
        Output.setEditable(false);
        outputScrollPane = new JScrollPane(Output);
        outputScrollPane.setPreferredSize(new Dimension(100, 150));
        outputScrollPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);

        add(outputScrollPane, BorderLayout.CENTER);

        clickMe = new JButton("click Me");
        add(clickMe, BorderLayout.SOUTH);

        execService = Executors.newSingleThreadExecutor();
        processThread = new ProcessThread(Output);
        execService.submit(processThread);

        clickMe.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {

                SwingUtilities.invokeLater(new Runnable() {

                    @Override
                    public void run() {
                        processThread.write("some command\n"); //does nothing (doesn't update JTextArea with the process' response)
                    }
                });
            }
        });

        setVisible(true);
    }
}
进程线程类:

public class ProcessThread implements Runnable {

     private JTextArea ta;

     private WriteWorker writeWorker;
     private ReadWorker readWorker;
     private CountDownLatch shutDownLatch;

     public ProcessThread(JTextArea ta) {
            this.ta = ta;
        }

     public void write(String text) {
            if (writeWorker != null) {
                if (writeWorker.getState() == SwingWorker.StateValue.STARTED) {
                    writeWorker.write(text);
                } else {
                    throw new IllegalStateException("Write worker is not running");
                }
            } else {
                throw new NullPointerException("Write worker is null");
            }
        }

     public void close() {
            if (writeWorker != null) {
                writeWorker.cancel(true);
            }
            if (readWorker != null) {
                readWorker.cancel(true);
            }

            // Force the CountDownLatch to release
            if (shutDownLatch != null) {
                shutDownLatch.countDown();
                shutDownLatch.countDown();
            }
        }

    @Override
    public void run() {
        try {
            Process myProcess;
            myProcess = new ProcessBuilder("C:\\Folder\\executable.exe").start();
            InputStream processInputStream = myProcess.getInputStream();
            OutputStream processOutputStream = myProcess.getOutputStream();

            writeWorker = new WriteWorker(processOutputStream);
            readWorker = new ReadWorker(processInputStream, ta);

            writeWorker.addPropertyChangeListener(new PropertyChangeHandler());
            readWorker.addPropertyChangeListener(new PropertyChangeHandler());

            writeWorker.execute();
            readWorker.execute();

            shutDownLatch = new CountDownLatch(2);
            shutDownLatch.await();
        } catch (IOException | InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    protected class PropertyChangeHandler implements PropertyChangeListener {

        @Override
        public void propertyChange(PropertyChangeEvent evt) {
            SwingWorker worker = (SwingWorker) evt.getSource();
            if (worker.getState() == SwingWorker.StateValue.DONE) {
                shutDownLatch.countDown();

                // Not interested in the return value, only interested in the
                // exception if one was thrown...
                try {
                    worker.get();
                } catch (InterruptedException | ExecutionException ex) {
                    // Resync the error with the UI, probably using SwingUtilities.invokeLater
                    // and call some error handling method
                    ex.printStackTrace();
                }
            }
        }

    }
}
ReadWorker类:

public class ReadWorker extends SwingWorker<Void,String> {

     private InputStream is;
     private JTextArea ta;

        public ReadWorker(InputStream is, JTextArea ta) {
            this.is = is;
            this.ta = ta;
        }

    @Override
    protected Void doInBackground() throws Exception {
        byte[] buffer = new byte[4096];
        int bytesRead = -1;
        while (!isCancelled() && (bytesRead = is.read(buffer)) != -1) {
            String text = new String(buffer, 0, bytesRead);
            publish(text);
        }
        return null;
    }

    @Override
    protected void process(List<String> chunks) {
        for (String text : chunks) {
            ta.append(text);
        }
    }
}
public class WriteWorker extends SwingWorker {

    private OutputStream os;

    private List<String> queue = new ArrayList<String>(25);
    private ReentrantLock queueLock = new ReentrantLock();
    private Condition queueCondition = queueLock.newCondition();

    @Override
    protected Object doInBackground() throws Exception {
        while (!isCancelled()) {
            String text = null;
            while (text == null && !isCancelled()) {
                queueLock.lock();
                try {
                    if (queue.isEmpty()) {
                        queueCondition.await();
                    }

                    if (!queue.isEmpty()) {
                        text = queue.remove(0);
                    }
                } finally {
                    queueLock.unlock();
                }
                if (text != null) {
                    os.write(text.getBytes());
                }
            }
        }
        return null;
    }

     public WriteWorker(OutputStream os) {
            this.os = os;
        }

     public void write(String text) {
            queueLock.lock();
            try {
                queue.add(text);
                queueCondition.signal();
            } finally {
                queueLock.unlock();
            }
     }
}

我做错了什么?为什么?

你会为此自责的

你只需要一句话

任何时候,当您向stdin写入文件(或任何流)时,请确保刷新缓冲区。

WriteWorker
doInBackground()
方法中,您需要添加:

os.flush();
调用
os.write(…)

因此,您的
doInBackground()
方法应该如下所示:

@Override
protected Object doInBackground() throws Exception {
    while (!isCancelled()) {
        String text = null;
        while (text == null && !isCancelled()) {
            queueLock.lock();
            try {
                if (queue.isEmpty()) {
                    queueCondition.await();
                }

                if (!queue.isEmpty()) {
                    text = queue.remove(0);
                }
            } finally {
                queueLock.unlock();
            }
            if (text != null) {
                os.write(text.getBytes());
                os.flush();
            }
        }
    }
    return null;
}

顺便说一句,这个过程将是一个国际象棋引擎。我需要向它发送命令,然后实时显示它的评估结果。可以从这里下载引擎exe:当我发送命令“uci\n”时,引擎的响应不会显示在JTextArea上
@Override
protected Object doInBackground() throws Exception {
    while (!isCancelled()) {
        String text = null;
        while (text == null && !isCancelled()) {
            queueLock.lock();
            try {
                if (queue.isEmpty()) {
                    queueCondition.await();
                }

                if (!queue.isEmpty()) {
                    text = queue.remove(0);
                }
            } finally {
                queueLock.unlock();
            }
            if (text != null) {
                os.write(text.getBytes());
                os.flush();
            }
        }
    }
    return null;
}