我几天前在这里发布了同样的问题(Java reading standard output from an external program using inputstream),我在阅读时处理了一个块时发现了一些很好的建议(while(is.read())!= -1 )),但我仍然无法解决问题。
在阅读了这个类似问题的答案后,
Java InputStream blocking read (尤其是Guss发布的答案),
我开始相信,如果程序是交互式的,那么使用is.read()!= -1条件循环输入流是不起作用的(即需要来自用户的多个输入并在后续输入时显示其他输出,只有在给出显式退出命令时才退出程序)。我承认我对多线程知之甚少,但我认为我需要的是一种在需要用户输入时立即暂停输入流线程(stdout,stderr各一个)的机制,并在输入后恢复提供以防止阻止。以下是我当前的代码,该代码在指示的行上遇到阻塞:
EGMProcess egm = new EGMProcess(new String[]{directory + "/egm", "-o", "CasinoA", "-v", "VendorA", "-s", "localhost:8080/gls/MessageRobot.action ", "-E", "glss_env_cert.pem", "-S", "glss_sig_cert.pem", "-C", "glsc_sig_cert.pem", "-d", "config", "-L", "config/log.txt", "-H", "GLSA-SampleHost"}, new String[]{"PATH=${PATH}"}, directory);egm.execute(); BufferedReader stdout = new BufferedReader(new InputStreamReader(egm.getInputStream())); BufferedReader stderr = new BufferedReader(new InputStreamReader(egm.getErrorStream())); EGMStreamGobbler stdoutprocessor = new EGMStreamGobbler(stdout, egm); EGMStreamGobbler stderrprocessor = new EGMStreamGobbler(stderr, egm); BufferedWriter stdin = new BufferedWriter(new OutputStreamWriter(egm.getOutputStream())); stderrprocessor.run(); //<-- the block occurs here! stdoutprocessor.run(); //EGM/Agent test cases //check bootstrap menu if(!checkSimpleResult("******** EGM Bootstrap Menu **********", egm)) { String stdoutdump = egm.getStdOut(); egm.cleanup(); throw new Exception("can't find '******** EGM Bootstrap Menu **********'" + "in the stdout" + "\nStandard Output Dump:\n" + stdoutdump); } //select bootstrap stdin.write("1".toCharArray()); stdin.flush(); if(!checkSimpleResult("Enter port to receive msgs pushed from server ('0' for no push support)", egm)){ String stdoutdump = egm.getStdOut(); egm.cleanup(); throw new Exception("can't find 'Enter port to receive msgs pushed from server ('0' for no push support)'" + "in the stdout" + "\nStandard Output Dump:\n" + stdoutdump); }
...
public class EGMStreamGobbler implements Runnable{
private BufferedReader instream; private EGMProcess egm; public EGMStreamGobbler(BufferedReader isr, EGMProcess aEGM) { instream = isr; egm = aEGM; } public void run() { try{ int c; while((c = instream.read()) != 1) { egm.processStdOutStream((char)c); } } catch(IOException e) { e.printStackTrace(); } }
}
我为代码的长度道歉,但我的问题是,
1)有没有办法控制输入流(stdout,stderr)的过程而不使用read()?或者我只是严厉执行这个?
2)多线程是否是开发输入流和编写输出过程的正确策略?
PS:如果有人能提出解决方案的类似问题,那将对我有所帮助!答案 0 :(得分:8)
而不是
stderrprocessor.run(); //<-- the block occurs here!
stdoutprocessor.run();
你需要启动线程:
Thread errThread = new Thread(stderrprocessor);
errThread.setDaemon( true );
errThread.start();
Thread outThread = new Thread(stdoutprocessor);
outThread.setDaemon( true );
outThread.start();
run()
只是Runnable
中指定的方法。 Thread.start()
在新run()
Runnable
上调用Thread
。
答案 1 :(得分:2)
答案 2 :(得分:1)
首先,您需要阅读Thread和Runnable。你不直接调用Runnable.run(),你设置Threads来做那个,然后启动线程。
但更重要的是,三个独立线程的存在意味着需要一些精心设计。为什么3线程?刚刚开始的两个,主要的一个。
我认为您的应用程序的一般想法是等待某些输出到达,解释它并因此向您正在控制的应用程序发送命令?
所以你的主线程需要等待其中一个读者线程说“啊哈!这很有意思,更好地问用户他想做什么。”
换句话说,您需要在读者和作者之间建立一些沟通机制。 这可以使用Java的事件机制来实现。我害怕更多的阅读。
答案 3 :(得分:1)
这不是创建nio的原因吗?
我对nio中的频道了解不多,但this answer可能会有所帮助。它显示了如何使用nio读取文件。可能有用。