2014-01-16 8 views
0

Runtime.getRuntime(). exec()를 통해 실행 된 출력 또는 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"가 올바르게 추가된다는 것입니다. 왜 그런가?

건배.

+4

아마도 입력 스트림이 아닌 프로세스의 오류 스트림에 기록되기 때문일 수 있습니다. – assylias

답변

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

그뿐만 아니라, InputStream을 완전히 사용하지 않고 대신'redirectOutput (log)'를 사용할 수 있습니다. – VGR

+0

정말로 좋은 점. – assylias

1

process.getInputStream()을 통해 오류를 사용할 수 없으므로 process.getErrorStream()을 사용해야합니다. 다른 방법으로는 먼저 processBuilder.redirectErrorStream(true)을 사용하는 것입니다. 이렇게하면 process.getInputStream()에서 stdout과 stderr를 모두 사용할 수 있습니다.

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 열려진 표준 출력에 모두 기록하는 경우, 프로세스가 차단합니다 : 그것은 단지 열려진에서 읽을 때, 거기에 아무도 stdout 버퍼의 바이트를 읽을 수 없습니다. 이 버퍼가 채워지면 WriteToFile은 다음 println()에서 차단됩니다. 예외가 작성되기 전에 이런 일이 발생한다고 가정하면 두 프로세스 모두 교착 상태가되며 각 프로세스는 다른 프로세스가 첫 번째 이동을 기다리고 있습니다. 솔루션 : stdout을 소비하고 stderr을 소비하는 두 개의 스레드를 생성합니다.

기타 (사소한) 문제 : (2) 대신에 차례로하는 BufferedReader 내부에 싸여있다, InputStreamReader에서 InputStream 포장의 스캐너 클래스를 사용할 수 있습니다 생성자는 InputStream를 취할 수 있습니다 그것은 당신에게 내의 readLine을 제공합니다() 메소드가 필요합니다.

(3) log.createNewFile();에서 유일한 용도 인 경우 log 변수를 만들 필요가 없습니다. FileWriter 개체가 출력 파일을 생성합니다.

(4) FileWriter 대신 PrintWriter 개체를 사용하고 싶을 것입니다. 전자는 println()을 제공하여 출력을 줄 단위로 인쇄 할 수 있습니다.