无法从Java进程读取InputStream(Runtime.getRuntime()。exec()或ProcessBuilder)

我正在尝试使用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()); } 

我意识到这个问题已经过时了,但我只是遇到了同样的问题。 为了解决这个问题,我使用了这段代码。

  List 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)合并redirectErrorStream(true)

你需要在一个线程中完成这项工作。 例如,记录标准输出:

 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。

我有一个C程序打印到stdout这个问题…

在C代码中使用fflush(stdout)redirectErrorStream(true)解决方案为我做了诀窍。

经过几天的努力,并尝试了很多选择后, 我找到了解决方案 。 使用jdk 8 u 25在Ubuntu 14.04 x64上工作。 这个codereviewpost给了我提示。

诀窍是在使用InputStream#available()读取任何内容之前使用InputStream#available() 。 我个人有两个线程,一个用于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; } } 

我遇到了与ftp相同的问题,直到我注意到ftp检测到它是否是从终端调用的。

当没有从终端调用ftp时,它会暂停任何输出到stdout,除非提供了详细(-v)选项。

流阻塞的原因是没有任何内容写入它们。

我有同样的问题。 不幸

 processBuilder.redirectErrorStream(true); 

不适合我; 它让我知道出了什么问题。 尝试使用以下代码行来显示stderr内容:

 BufferedReader err= new BufferedReader(new InputStreamReader(process.getErrorStream())); 

它帮助我找出了运行每个线程的终端命令出了什么问题。