无法从 Java Process(Runtime.getRuntime().exec() 或 ProcessBuilder)读取 InputStream

发布于 2024-09-08 05:25:48 字数 1265 浏览 5 评论 0原文

我正在尝试使用 Java 从外部启动一个进程,但无法从其输入流中读取任何内容。

如果我使用“ls”、“ps”或“kill”等命令启动进程,一切都会正常。我可以启动该进程并获取有关该进程的 InputStream 或 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());     
   } 

I'm trying to start a process externally with Java and can't read anything from its 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.

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.

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());     
   } 

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

泅渡 2024-09-15 05:25:48

我意识到这个问题很老了,但我刚刚遇到了同样的问题。为了解决这个问题,我使用了这段代码。

 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) 手动合并它们

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)

ま昔日黯然 2024-09-15 05:25:48

我在 C 程序打印到 stdout 时遇到了这个问题...

C 代码中带有 fflush(stdout)redirectErrorStream(true) 解决方案为我解决了这个问题。

I had this issue with a C program printing to stdout...

The redirectErrorStream(true) solution with a fflush(stdout) in the C code did the trick for me.

丶情人眼里出诗心の 2024-09-15 05:25:48

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

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。

You need to do this work in a Thread. For example to log the standard output:

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.

梦里人 2024-09-15 05:25:48

经过几天的努力并尝试了多种选择我找到了解决方案。在 Ubuntu 14.04 x64 上工作,使用 jdk 8 u 25。 这篇代码评论文章< /a> 给了我提示。

诀窍是在使用 BufferedReader 读取任何内容之前使用 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;
    }
}

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 post gave me the hint.

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()

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;
    }
}
在巴黎塔顶看东京樱花 2024-09-15 05:25:48

我遇到了完全相同的问题。不幸的是,

processBuilder.redirectErrorStream(true); 

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

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

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

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:

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

It helped me figure out what was wrong with my terminal commands running through each thread.

小…红帽 2024-09-15 05:25:48

我对 ftp 也有同样的问题,直到我注意到 ftp 会检测它是否是从终端调用的。

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

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

I had the same problem with ftp, until I noticed that ftp detects if it is called from a terminal or not.

When ftp is not called from a terminal, it suspends any output to stdout, unless the verbose (-v) option is supplied.

The reason for the streams blocking is that nothing is written to them.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文