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

时间:2014-01-16 10:01:57

标签: java

我正在尝试在日志文件上写入输出或通过Runtime.getRuntime()。exec()启动的Java程序。我正在使用以下代码。

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”假设在终端上写一个例外,但不幸的是,我没有得到任何东西。奇怪的是,如果我通过“echo test”更改此命令,将在日志文件的末尾正确添加“test”。知道为什么吗?

干杯。

3 个答案:

答案 0 :(得分:2)

最有可能的原因是异常发生在错误流中。一种选择是重定向错误流:process.getErrorStream()

或者,您可以使用a ProcessBuilder

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

答案 1 :(得分:1)

process.getInputStream()无法提供错误,您需要使用process.getErrorStream()。另一种方法是首先使用processBuilder.redirectErrorStream(true)。这将导致stdout和stderr在process.getInputStream()上可用。

答案 2 :(得分:0)

这里有几个问题。以下是我将如何编写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)最重要的是:如果WriteToFile写入stderr和stdout,你的进程将阻塞:因为它只从stderr读取,所以没有人从stdout缓冲区读取字节。一旦此缓冲区填满WriteToFile将阻止下一个println()。假设在写入异常之前发生这种情况,两个进程都将陷入死锁状态,每个进程都在等待另一个进程进行第一次移动。解决方案:生成两个线程,一个用于消耗stdout,另一个用于消耗stderr。

其他(次要)问题: (2)而不是将InputStream包装在InputStreamReader中,而BufferedReader又包含在log中,您可以使用Scanner类:它的构造函数可以使用InputStream,它会为您提供您需要的readLine()方法。

(3)如果在log.createNewFile();中使用唯一目的,则无需创建FileWriter变量 - 您的PrintWriter对象将为您创建输出文件。 / p>

(4)您可能想要使用FileWriter对象而不是println()。前者为您提供{{1}},可让您逐行打印输出。