无法从 Java 进程(Runtime.getRuntime().exec() 或 ProcessBuilder)读取 InputStream
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/3159913/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Unable to read InputStream from Java Process (Runtime.getRuntime().exec() or ProcessBuilder)
提问by msg
I'm trying to start a process externally with Java and can't read anything from its InputStream.
我正在尝试使用 Java 从外部启动一个进程,但无法从其 InputStream 中读取任何内容。
If I'm starting a process with commands like "ls", "ps" or "kill" everything works fine. I can start the process and get information either on the InputStream or the ErrorStream of the Process.
如果我使用“ls”、“ps”或“kill”等命令启动进程,一切正常。我可以启动流程并获取有关流程的 InputStream 或 ErrorStream 的信息。
If I try to use a command like "ftp" or "telnet" both InputStream and ErrorStream are blocking my program when trying to read. No information is passed through these streams at any time.
如果我尝试使用诸如“ftp”或“telnet”之类的命令,则 InputStream 和 ErrorStream 在尝试读取时都会阻塞我的程序。任何时候都不会通过这些流传递任何信息。
Can anyone explain the behavior? Is it just not possible with these commands or do I have an issue with my implementation?
任何人都可以解释这种行为吗?这些命令是不可能的,还是我的实现有问题?
String processName = _configuration.getProgramCommand().getCommand();
ProcessBuilder procBuilder = new ProcessBuilder(processName);
System.out.println("Starting process "+processName);
_proc = Runtime.getRuntime().exec(processName);// procBuilder.start();
if(!procBuilder.redirectErrorStream()) {
_errorWorker = new ProcessErrorWorker(_proc);
_errorWorker.start();
}
String proc_start_answer = _configuration.getNextCommand().getCommand();
System.out.println("Waiting for process answer '"+proc_start_answer+"'");
BufferedReader input = new BufferedReader(new InputStreamReader(_proc.getInputStream()));
String answer = "";
try {
System.out.println("inputstream ready: "+input.ready());
answer+=input.readLine();
System.out.println("process answer: "+answer);
input.close();
} catch(Exception e) {
System.out.print(e.getMessage());
}
回答by Hendrik Brummermann
You need to do this work in a Thread. For example to log the standard output:
您需要在 Thread 中完成这项工作。例如记录标准输出:
Process process = Runtime.getRuntime().exec(command);
LogStreamReader lsr = new LogStreamReader(process.getInputStream());
Thread thread = new Thread(lsr, "LogStreamReader");
thread.start();
public class LogStreamReader implements Runnable {
private BufferedReader reader;
public LogStreamReader(InputStream is) {
this.reader = new BufferedReader(new InputStreamReader(is));
}
public void run() {
try {
String line = reader.readLine();
while (line != null) {
System.out.println(line);
line = reader.readLine();
}
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
Then you need a second thread for input handling. And you might want to deal with stderr just like stdout.
然后你需要第二个线程来处理输入。您可能想像处理 stdout 一样处理 stderr。
回答by Andrew T Finnell
I realize this is question is old, but I just experienced the same problem. In order to fix this I used this code..
我意识到这是一个老问题,但我刚刚遇到了同样的问题。为了解决这个问题,我使用了这段代码..
List<String> commandAndParameters = ...;
File dir = ...; // CWD for process
ProcessBuilder builder = new ProcessBuilder();
builder.redirectErrorStream(true); // This is the important part
builder.command(commandAndParameters);
builder.directory(dir);
Process process = builder.start();
InputStream is = process.getInputStream();
It appears the process is expecting you to also read from the Error stream. The best fix to this is to merge the input and error stream together.
该过程似乎希望您也从错误流中读取。对此的最佳解决方法是将输入和错误流合并在一起。
Update
更新
I didn't see that you attempted to read from the error stream also. It could just be that you need to merge them manually with redirectErrorStream(true)
我没有看到您也尝试从错误流中读取数据。可能只是您需要手动将它们与redirectErrorStream(true)
回答by Pierre Brunetti
I had this issue with a C program printing to stdout...
我在将 C 程序打印到标准输出时遇到了这个问题...
The redirectErrorStream(true)
solution with a fflush(stdout)
in the C code did the trick for me.
C 代码中redirectErrorStream(true)
带有 a的解决方案fflush(stdout)
对我有用。
回答by Zahra
I had the exact same problem. Unfortunately
我有同样的问题。很遗憾
processBuilder.redirectErrorStream(true);
didn't work for me; it gave me an idea of what is wrong though. Try using following line of code to display stderr contents:
对我不起作用;它让我知道出了什么问题。尝试使用以下代码行显示 stderr 内容:
BufferedReader err=
new BufferedReader(new InputStreamReader(process.getErrorStream()));
It helped me figure out what was wrong with my terminal commands running through each thread.
它帮助我弄清楚我的终端命令在每个线程中运行时出了什么问题。
回答by Clausen
I had the same problem with ftp, until I noticed that ftp detects if it is called from a terminal or not.
我对 ftp 有同样的问题,直到我注意到 ftp 检测它是否从终端调用。
When ftp is not called from a terminal, it suspends any output to stdout, unless the verbose (-v) option is supplied.
当没有从终端调用 ftp 时,它会将任何输出挂起到 stdout,除非提供了详细 (-v) 选项。
The reason for the streams blocking is that nothing is written to them.
流阻塞的原因是没有向它们写入任何内容。
回答by Jules Randolph
After struggling for days, and trying many options I found a solution. Working on Ubuntu 14.04 x64, with jdk 8 u 25. This codereview postgave me the hint.
经过几天的努力,并尝试了很多选择,我找到了一个解决方案。使用 jdk 8 u 25 在 Ubuntu 14.04 x64 上工作。这篇 codereview 帖子给了我提示。
The trick is to use InputStream#available()
before reading anything with the BufferedReader
. I personally have two threads, one for stdout and the other for stderr. Here is a simple running snippet I extrapolated from my program. If you don't want to read all, just jump to readLine()
诀窍是使用InputStream#available()
阅读与任何事情之前BufferedReader
。我个人有两个线程,一个用于 stdout,另一个用于 stderr。这是我从我的程序中推断出来的一个简单的运行片段。如果您不想阅读所有内容,请跳至readLine()
import org.apache.commons.io.IOUtils;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.InputStream;
import java.io.BufferedReader;
import java.nio.charset.Charset;
public class LogHandler {
private BufferedReader bufferedReader;
private InputStream inputStream;
private Thread thread;
private boolean isRunning;
public void open (InputStream inputStream) {
this.inputStream = inputStream;
this.bufferedReader = new BufferedReader(new InputStreamReader(inputStream, Charset.defaultCharset()));
isRunning = true ;
if(thread!=null){
thread = new Thread (()->{
while(isRunning) {
String line = null;
try {
line = readLine();
} catch (IOException e) {
isRunning = false;
}
if(line == null) {
try {
Thread.sleep(150);
} catch (InterruptedException ie) {
isRunning=false;
Thread.currentThread().interrupt();
}
} else {
System.out.println(line);
}
}
});
} else throw new IllegalStateException("The logger is already running");
thread.start();
}
public void close() throws InterruptedException {
if(thread!=null){
thread.interrupt();
thread.join();
thread = null;
IOUtils.closeQuietly(inputStream);
} else throw new IllegalStateException("The logger is not running"); }
private String readLine() throws IOException {
if(inputStream.available()>0) { // <--------- THIS IS IT
int kar = bufferedReader.read();
if (kar != -1) {
StringBuilder buffer = new StringBuilder(30);
while (kar != -1 && kar != (int) '\n') {
buffer.append((char) kar);
kar = bufferedReader.read();
}
return buffer.toString();
}
}
return null;
}
}