我有slcanterm.exe命令行实用工具,用我的USB-CAN适配器执行终端功能,连接到PC.我需要从Java应用程序启动这个实用程序,然后在循环中对这个终端进行读写。我的问题是我不能让InputStream和OutputStream一起工作:
System.out.println( "hello" );
String line;
OutputStream stdin = null;
InputStream stderr = null;
InputStream stdout = null;
Process process = Runtime.getRuntime ().exec ("cmd.exe");
stdin = process.getOutputStream ();
stderr = process.getErrorStream ();
stdout = process.getInputStream ();
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(stdin));
BufferedReader reader = new BufferedReader (new InputStreamReader (stdout));
line = "slcanterm.exe" + "\n";
writer.write(line );
writer.flush();
// If I uncomment this line reader.readLine() loop is stucked
//writer.close();
while ((line = reader.readLine ()) != null)
System.out.println ("[Stdout] " + line);
System.out.println( "buy" );如果我不关闭writer流,while ((line = reader.readLine ()) != null)就会被塞住。我需要执行reader.readLine ()和writer.write(line )在循环中的工作。有什么解决办法吗?
发布于 2015-06-17 09:17:05
System.out.println( "hello" );
String line;
Process process = Runtime.getRuntime ().exec ("cmd.exe /c slcanterm.exe");
InputStream stderr = process.getErrorStream ();
InputStream stdout = process.getInputStream ();
BufferedReader reader = new BufferedReader (new InputStreamReader(stdout));
BufferedReader error = new BufferedReader (new InputStreamReader(stderr));
new Thread() {
public void run() {
try {
String err;
while ((err = error.readLine ()) != null)
System.out.println ("[Stderr] " + err);
} catch (Exception e) {
e.printStackTrace();
}
}}.start();
while ((line = reader.readLine ()) != null)
System.out.println ("[Stdout] " + line);
System.out.println( "buy" );发布于 2015-06-17 08:44:12
1)您的代码(基本上)是正确的。但是,我遇到了一个类似的问题,另一个进程在关闭它的输入流时没有很好的响应。如果关闭进程的输入流(编写器),则流程实际上会看到他的输入流已关闭,并在试图从中读取时失败。在我的例子中,当他的阅读失败时,我开始的过程没有得到很好的响应。这似乎也是同样的问题。
2)您可以通过直接启动slcanterm.exe而不使用cmd.exe来规避这一切。
3)我看到的另一种可能性是,您只添加"\n",也许cmd.exe需要"\n\r“。
发布于 2015-06-17 08:47:09
输出流将保持打开状态,直到进程退出为止。当进程决定终止时退出,它将显式终止,或者通过关闭输入流隐式地终止,例如。
这意味着您的readLine将被阻塞,直到cmd.exe有更多的输出,但是,由于您没有发送更多的命令,所以没有任何命令。永远也不会是。
在简单的情况下,您可以关闭输入或写入exit命令来关闭控制台。如果slcanterm.exe是您想要运行的唯一程序,那么您可以直接启动该进程。如果您想要运行更多的命令,那么您需要一种方法来检测错误(不要忽略错误流)或检测命令的输出已经终止。如果运行的命令没有一致的最后一行,那么可以将echo ---MARKER---写入stdin并检测该行何时出现(这意味着最后一个命令已经终止,echo已被执行)。
很多可能性。这取决于你想做什么。
下面的课演示了我所建议的简单技巧。另外,它确保了echo off,并且忽略了所有不是命令输出的内容(因为cmd.exe输出每个输入字符)。
class CommandRunner implements Closeable {
private Process cmd;
private OutputStreamWriter stdin;
private BufferedReader stderr;
private BufferedReader stdout;
private static class ArtificialOutput {
public List<String> inputLines;
public String finalMarker;
public ArtificialOutput(List<String> inputLines, String finalMarker) {
super();
this.inputLines = inputLines;
this.finalMarker = finalMarker;
}
}
public CommandRunner() throws IOException {
cmd = Runtime.getRuntime().exec("cmd.exe");
stdin = new OutputStreamWriter(cmd.getOutputStream());
stderr = new BufferedReader(new InputStreamReader(cmd.getErrorStream()));
stdout = new BufferedReader(new InputStreamReader(cmd.getInputStream()));
// turn off echo of commands (also skips any console header lines)
execute("echo off", StdinWriter.WRITE_NOTHING, StdoutProcessor.IGNORE);
}
@Override
public void close() throws IOException {
stdin.close();
stdout.close();
stderr.close();
cmd.destroy();
}
public void execute(String command, StdinWriter writer, StdoutProcessor processor) throws IOException {
processOutput(executeCommand(command, writer), processor);
}
private ArtificialOutput executeCommand(String command, StdinWriter writer) throws IOException {
List<String> lines = new ArrayList<String>();
// add command as input line
lines.add(command);
// add all custom input lines
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
try (OutputStreamWriter bufferWriter = new OutputStreamWriter(buffer)) {
writer.write(bufferWriter);
}
try (BufferedReader reader = new BufferedReader(new InputStreamReader(new ByteArrayInputStream(buffer.toByteArray())))) {
String line = null;
while ((line = reader.readLine()) != null) {
lines.add(line);
}
}
// add stdout and sterr markers as input lines
String marker = "--- MARKER " + System.currentTimeMillis() + Math.random();
lines.add("echo " + marker + ">&2");
lines.add("echo " + marker);
// write everything to stdin
for (String line : lines) {
stdin.write(line + System.lineSeparator());
}
stdin.flush();
// our artificial outputs (with echo off) are the input lines and the closing marker
return new ArtificialOutput(lines, marker);
}
private void processOutput(ArtificialOutput artificialOutput, StdoutProcessor processor) throws IOException {
byte[] output = readUntilMarker(artificialOutput, stdout);
byte[] errors = readUntilMarker(artificialOutput, stderr);
if (errors.length > 0) {
processor.processError(new BufferedReader(new InputStreamReader(new ByteArrayInputStream(errors))));
}
processor.processOuput(new BufferedReader(new InputStreamReader(new ByteArrayInputStream(output))));
}
private byte[] readUntilMarker(ArtificialOutput artificialOutput, BufferedReader reader) throws IOException {
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
try (BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(buffer))) {;
String line;
while ((line = reader.readLine()) != null) {
// ignore input lines because cmd.exe outputs every input character
if (artificialOutput.inputLines.remove(line)) {
continue;
}
// the final marker indicates the command has ended
if (line.equals(artificialOutput.finalMarker)) {
break;
}
// everything else is the command output
writer.write(line + System.lineSeparator());
}
}
return buffer.toByteArray();
}
}有了这个类,您可以在程序中这样做:
try (CommandRunner cmd = new CommandRunner()) {
cmd.execute("dir", StdinWriter.WRITE_NOTHING, StdoutProcessor.PRINT);
cmd.execute("echo something", StdinWriter.WRITE_NOTHING, StdoutProcessor.PRINT);
}https://stackoverflow.com/questions/30886148
复制相似问题