我正在尝试使用Java从外部启动一个进程,并且无法从其InputStream中读取任何内容。
如果我使用“ls”,“ps”或“kill”等命令启动进程,一切正常。我可以启动该过程并获取有关InputStream或Process的ErrorStream的信息。
如果我尝试使用“ftp”或“telnet”之类的命令,则在尝试读取时,InputStream和ErrorStream都会阻止我的程序。任何时候都不会通过这些流传递任何信息。
任何人都可以解释这种行为吗?这些命令是不可能的,还是我的实现有问题?
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());
}
答案 0 :(得分:11)
我意识到这个问题已经过时了,但我刚遇到同样的问题。为了解决这个问题,我使用了这段代码..
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();
似乎该过程期望您也从错误流中读取。解决此问题的最佳方法是将输入和错误流合并在一起。
<强>更新强>
我没有看到您也试图从错误流中读取。可能只需要将它们与redirectErrorStream(true)
答案 1 :(得分:6)
您需要在线程中执行此操作。例如,记录标准输出:
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();
}
}
}
然后你需要第二个线程来进行输入处理。你可能想像stdout一样处理stderr。
答案 2 :(得分:6)
我有一个C程序打印到stdout的问题......
C代码中带有redirectErrorStream(true)
的{{1}}解决方案为我做了诀窍。
答案 3 :(得分:4)
经过几天的努力,并尝试了很多选择我找到了解决方案。使用jdk 8 u 25工作在Ubuntu 14.04 x64上。This codereview post给了我提示。
诀窍是在使用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;
}
}
答案 4 :(得分:2)
我遇到了与ftp相同的问题,直到我注意到ftp检测到它是否是从终端调用的。
当没有从终端调用ftp时,它会暂停任何输出到stdout,除非提供了详细(-v)选项。
流阻塞的原因是没有任何内容写入它们。
答案 5 :(得分:1)
我遇到了完全相同的问题。不幸的是
processBuilder.redirectErrorStream(true);
对我不起作用;它让我知道出了什么问题。尝试使用以下代码行来显示stderr内容:
BufferedReader err=
new BufferedReader(new InputStreamReader(process.getErrorStream()));
它帮助我找出了运行每个线程的终端命令出了什么问题。