【问题标题】:Printing Runtime exec() OutputStream to console将运行时 exec() OutputStream 打印到控制台
【发布时间】:2010-10-14 17:51:23
【问题描述】:

我正在尝试将exec() 发起的ProcessOutputStream 发送到控制台。如何做到这一点?

这是一些不完整的代码:

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream;
import java.io.Reader;

public class RuntimeTests
{
    public static void main(String[] args)
    {
        File path = new File("C:\\Dir\\Dir2");
        String command = "cmd /c dir";
        Reader rdr = null;
        PrintStream prtStrm = System.out;
        try
        {
            Runtime terminal = Runtime.getRuntime();

            OutputStream rtm = terminal.exec(command, null, path).getOutputStream();
            prtStrm = new PrintStream(rtm);
            prtStrm.println();
        } 
        catch (IOException e)
        {
            e.printStackTrace();
        }
    }
}

【问题讨论】:

    标签: java stream runtime runtime.exec printstream


    【解决方案1】:

    我最近遇到了这个问题,只是想提一下,从 java 7 开始,process builder api 已经扩展。现在可以通过以下方式解决此问题:

    ProcessBuilder pb = new ProcessBuilder("yourcommand");
    pb.redirectOutput(Redirect.INHERIT);
    pb.redirectError(Redirect.INHERIT);
    Process p = pb.start();
    

    【讨论】:

    • 完美而优雅的答案。如果您可以使用 Java 7,那么这绝对是您的最佳选择。
    • 这是最好的答案,即使上面有好的,也总是尽量使用Java工具箱默认自带的工具。 Java 7/8 是一种功能极其强大的语言 - 具有不断扩展但高效的工具包。
    • 我在 Java 11 中收到以下错误消息:“通过直接写入分叉 JVM 1 中的本机流导致 STDOUT 损坏。”这个解决方案是否可能不再适用于 Java 11?
    【解决方案2】:

    我相信这就是您正在寻找的:

      String line;
      Process p = Runtime.getRuntime().exec(...);
      BufferedReader input = new BufferedReader(new InputStreamReader(p.getInputStream()));
      while ((line = input.readLine()) != null) {
        System.out.println(line);
      }
      input.close();
    

    【讨论】:

    • 我对您的解决方案有一个疑问:是否不需要使用 process.waitFor()?它也可以不使用,但为什么? InputStreamReader 是否等到流结束?
    • 是的,API:如果由于到达流的末尾而没有可用的字节,则返回值-1。此方法一直阻塞,直到输入数据可用、检测到流结束或引发异常。
    • 添加redirectErrorStream(true) 以确保完整性。
    【解决方案3】:

    我遇到了类似的问题,我正在使用以下代码。

    Process p = Runtime.getRuntime().exec(".....");
    p.waitFor();
    
    String line;
    
    BufferedReader error = new BufferedReader(new InputStreamReader(p.getErrorStream()));
    while((line = error.readLine()) != null){
        System.out.println(line);
    }
    error.close();
    
    BufferedReader input = new BufferedReader(new InputStreamReader(p.getInputStream()));
    while((line=input.readLine()) != null){
        System.out.println(line);
    }
    
    input.close();
    
    OutputStream outputStream = p.getOutputStream();
    PrintStream printStream = new PrintStream(outputStream);
    printStream.println();
    printStream.flush();
    printStream.close();
    

    【讨论】:

      【解决方案4】:

      请参阅 Benjamin Gruenbaum 回答,涵盖自 Java 7 起可用的 ProcessBuilder API。

      您需要启动一个新线程来读取在Process.waitFor() 之后发生的进程输出。然后进程输出可以从该线程复制到控制台。

      Process.getOutputStream() 实际上是输入,即进程的标准输入。 Process.getInputStream()Process.getErrorStream() 返回 InputStream 对象,它们是进程的标准输出和标准错误。 InputStreams 和 OutputStream 是从调用者的角度来看的,这与进程的角度相反。

      进程的输出 stdout 是调用者的输入,因此调用者会得到一个getInputStream() 并从中读取标准输出:

      Process proc = Runtime.getRuntime().exec(cmdArr, env, cwdir);
      
      InputStreamReader isr = new InputStreamReader(proc.getInputStream());
      BufferedReader rdr = new BufferedReader(isr);
      while((line = rdr.readLine()) != null) { 
        System.out.println(line);
      } 
      
      isr = new InputStreamReader(proc.getErrorStream());
      rdr = new BufferedReader(isr);
      while((line = rdr.readLine()) != null) { 
        System.out.println(line);
      } 
      rc = proc.waitFor();  // Wait for the process to complete
      

      Process.getOutputStream() 用于调用者将数据“输出”到进程的标准输入中。可以在上面示例的第一行中创建 'proc' 之后添加此代码,以将数据发送到进程的标准输入:

      // Send data to stdin of the process (in development, needs input content)
      OutputStream os = proc.getOutputStream();
      Bytes content = new Bytes("Hello\nasdf\n adma");
      os.write(content.arr, content.off, content.length());
      os.close(); // should use try/finally or try/resource
      

      在读取输出之前执行上述操作。记得关闭OutputStream 操作系统(使用try/resource 或try/finally)。所以,进程知道标准输入是完整的,它可以完成对信息的处理。

      【讨论】:

      • 对于现在提出这个问题的每个人:向下滚动,下面有更好的答案
      • (答案被编辑为再次成为更好的答案。)
      【解决方案5】:

      我知道这是一个非常古老的问题,但上述答案的更好替代方案是

      ProcessBuilder builder = new ProcessBuilder(command);
      builder.inheritIO();
      Process p = builder.start();
      

      来自ProcessBuilder.inheritIO() 的文档,

      将子进程标准 I/O 的源和目标设置为 与当前 Java 进程相同。

      希望这对某人有所帮助!

      【讨论】:

        【解决方案6】:

        jcabi-log 尝试VerboseProcess

        String output = new VerboseProcess(new ProcessBuilder("foo.bat")).stdout();
        

        该类启动一个后台线程,监听输出流并记录它。

        【讨论】:

          【解决方案7】:

          如果你可以使用 commons-io 中的 org.apache.commons.io.IOUTils,

          System.out.println(IOUtils.toString(process.getInputStream()));
          System.err.println(IOUtils.toString(process.getErrorStream()));
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2013-03-29
            • 1970-01-01
            • 2011-12-03
            • 1970-01-01
            • 1970-01-01
            • 2016-04-04
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多