简体   繁体   English

使用Runtime.getRuntime()。exec()启动的Java程序的输出

[英]Output from Java program launched with Runtime.getRuntime().exec()

I'm trying to write on a log file the output or a Java program launched via Runtime.getRuntime().exec(). 我试图在日志文件上写输出或通过Runtime.getRuntime()。exec()启动的Java程序。 I'm using the following code. 我正在使用以下代码。

public class Thread_Write extends Thread {
    int id;

    public void run() {
        try {
            File log = new File("./log"+id+".txt");
            log.createNewFile();
            FileWriter fw = new FileWriter("./"+"log"+id+".txt",true);
            Runtime runtime = Runtime.getRuntime();
            Process process = runtime.exec("java WriteToFile "+id);
            InputStream is = process.getInputStream();
            InputStreamReader isr = new InputStreamReader(is);
            BufferedReader br = new BufferedReader(isr);
            String line;
            while ((line = br.readLine()) != null) {
                fw.write(line);
              }

        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public Thread_Write(int i) {
        super();
        this.id = i;
    }

    public static void main(String[] args) {
        for (int i =0 ; i<10;i++) {
            (new Thread_Write(i)).start();
        }
    }
}

"java WriteToFile id" is suppose to write an exception on the terminal, but unfortunately, I'm not getting anything. 假定“ java WriteToFile id”在终端上写入异常,但是不幸的是,我什么也没得到。 What's odd is that if I change this command bye "echo test", "test" will be properly added at the end of the log file. 奇怪的是,如果我通过“ echo test”更改此命令,则“ test”将正确添加到日志文件的末尾。 Any idea why ? 知道为什么吗?

Cheers. 干杯。

The likeliest reason is that the exception goes to the error stream. 最可能的原因是异常进入了错误流。 One option is to redirect the error stream too: process.getErrorStream() . 一种选择是也重定向错误流: process.getErrorStream()

Alternatively you can use a ProcessBuilder : 或者,您可以使用ProcessBuilder

ProcessBuilder pb = new ProcessBuilder("java", "WriteToFile", String.valueOf(id));
pb.redirectErrorStream(true);
pb.redirectOutput(log);
Process p = pb.start();

Errors are not available through process.getInputStream() , you need to instead use process.getErrorStream() . 错误不能通过process.getInputStream() ,您需要改为使用process.getErrorStream() An alternative is to first use processBuilder.redirectErrorStream(true) . 另一种选择是首先使用processBuilder.redirectErrorStream(true) This will cause both stdout and stderr to be available on process.getInputStream() . 这将导致stdout和stderr在process.getInputStream()上都可用。

There are several issues here. 这里有几个问题。 Here's how I would write the run() method (rationale follows): 这是我将如何编写run()方法的方法(如下所示):

public void run() {
  try {
    Process process = Runtime.getRuntime().exec("java WriteToFile " + id);
    Thread err = consume(process.getErrorStream(), 
        new FileOutputStream("./" + "log" + id + ".txt"));
    Thread std = consume(process.getInputStream(), 
        new FileOutputStream("./" + "log_stdout" + id + ".txt"));

    err.join();
    std.join();

  } catch (Exception e) {
    e.printStackTrace();
  } 
}

private Thread consume(final InputStream stream, 
    final OutputStream out) {
  Thread result = new Thread() {
    public void run() {
      PrintWriter pw = new PrintWriter(out, true);
      try (Scanner sc = new Scanner(stream)) {
        while (sc.hasNext()) {
          pw.println(sc.nextLine());
        }
      }
    }
  };
  result.start();
  return result;
}

(1) Most importantly: if WriteToFile writes to both stderr and stdout, your process will block: as it only reads from stderr, there's no one to read the bytes off of the stdout buffer. (1)最重要的是:如果WriteToFile写入stderr和stdout,则您的进程将阻塞:因为它仅从stderr读取,所以没有人可以从stdout缓冲区中读取字节。 Once this buffer fills up WriteToFile will block on the next println(). 一旦该缓冲区填满, WriteToFile将在下一个println()上阻塞。 Assuming this happens before an exception was written both processes will be deadlocked, each one waiting for the other one to make the first move. 假设这种情况在写入异常之前发生,则两个进程都将陷入僵局,每个进程都在等待另一个进程先行。 The solution: spawn two threads, one for consuming stdout and the other for consuming stderr. 解决方案:产生两个线程,一个用于使用stdout,另一个用于使用stderr。

Other (minor) issues: (2) Instead of wrapping InputStream in an InputStreamReader which, in turn, is wrapped inside a BufferedReader you can use the Scanner class: its constructor can take an InputStream and it gives you the readLine() method that you need. 其他(次要)问题:(2)您可以使用Scanner类,而不是将InputStream包裹在InputStreamReader中,而后者又包裹在BufferedReader :其构造函数可以采用InputStream,并为您提供readLine()方法需要。

(3) No need to create the log variable if it sole purpose is to be used in log.createNewFile(); (3)如果仅在log.createNewFile();使用log变量,则无需创建log变量log.createNewFile(); - the output file will be created for you by your FileWriter object. FileWriter对象将为您创建输出文件。

(4) You'd probably want to use a PrintWriter object rather than a FileWriter . (4)您可能想要使用PrintWriter对象而不是FileWriter The former gives you println() which lets you print the output line-by-line. 前者为您提供println() ,使您可以逐行打印输出。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM