2012-05-10 37 views
8

Trong các ngôn ngữ khác (như bashPython), khi chúng ta sinh ra một tiến trình con, quá trình mới này sẽ kế thừa giá trị stdout và stderr từ cha mẹ. Điều này có nghĩa là bất kỳ đầu ra nào từ quá trình con sẽ được in tới thiết bị đầu cuối cũng như đầu ra từ cha mẹ.Làm thế nào để chuyển hướng quá trình con stdout/stderr cho quá trình stdout/stderr chính trong Java?

Làm cách nào chúng ta có thể đạt được cùng một hành vi trong Java?

thử đầu tiên của tôi là:

proc = Runtime.getRuntime().exec(cmd); 

Nhưng nó sẽ không hoạt động. Dựa trên this answerthis answer, tôi đã thay thế mã với:

ProcessBuilder pb = new ProcessBuilder(cmd); 
pb.redirectOutput(System.out); 
pb.redirectError(System.err); 

Nhưng điều này thậm chí không biên dịch, như các đối số không phù hợp với các thông số phương pháp dự kiến.

Trả lời

13

Bạn cần phải đọc đầu ra và các luồng lỗi của quá trình bạn đã tạo và ghi đầu ra đến nơi bạn muốn nó đi (trong trường hợp của bạn là System.out và System.err).

Chỉnh sửa. Câu trả lời ở trên là chính xác cho java < 7. Tính đến 7 từ javadoc có vẻ là có thể thay vì gọi

processBuilder.redirectOutput(Redirect.INHERIT) 
+1

Bạn có nghĩa là tôi cần phải thực hiện một vòng lặp mà chỉ giữ đọc từ một dòng và viết trong một dòng khác? Xin lỗi, không khả thi. Quá nhiều công việc (có thể yêu cầu chạy trong một chủ đề mới, và nó giới thiệu rất nhiều điểm của các lỗi có thể). –

+2

Có thể sử dụng được hay không điều này đã từng được yêu cầu. Tôi vừa kiểm tra java 7 api và có vẻ như nó đã được giải quyết - bây giờ bạn có thể gọi redirectOutput đi qua trong Redirect.INHERIT để có được những gì bạn muốn. – henry

1

Đó chắc chắn có thể. Tác vụ Ant Java thực hiện điều này khi fork được đặt đúng. Tôi không nhớ tất cả các chi tiết, nhưng trên một cái nhìn nhanh chóng nó xuất hiện rằng hầu hết các phép thuật là trong PumpStreamHandler. Bạn có thể thử tìm một số cảm hứng từ đó.

+1

Trên thực tế dễ dàng hơn thế, nhưng chỉ áp dụng trong 1,7, mà bạn dường như đang sử dụng vì bạn đang sử dụng ProcessBuilder.redirectOutput() là làm pb.redirectOutput (Redirect.INHERIT). Mặc dù tôi chưa bao giờ làm điều đó. – asudell

3

Điều này không quá tệ. Tôi ban đầu cho biết "dễ dàng", sau đó tôi nhận ra rằng tôi muốn có để mã InputStreamConsumer:

public static class InputStreamConsumer extends Thread { 

    private InputStream is; 

    public InputStreamConsumer(InputStream is) { 
     this.is = is; 
    } 

    @Override 
    public void run() { 

     try { 
      int value = -1; 
      while ((value = is.read()) != -1) { 
       System.out.print((char)value); 
      } 
     } catch (IOException exp) { 
      exp.printStackTrace(); 
     } 
    } 
} 

private void captureOutput(Process p) { 

    InputStreamConsumer stdout; 
    InputStreamConsumer errout; 

    errout = new InputStreamConsumer(p.getErrorStream()); 
    stdout = new InputStreamConsumer(p.getInputStream()); 
    errout.start(); 
    stdout.start(); 
} 

.... chạy bên trong một cái gì đó giống như ...

ProcessBuilder pb = new ProcessBuilder("cmd.exe", "/D", "/C", myCommand, parm, parm...); 
    try { 
     System.out.println("Start "+myCommand); 
     Process myProcess = pb.start(); 
     captureOutput(myProcess); 

     int returnCode = myProcess.waitFor(); 
     System.out.println("myProcess: return code : "+returnCode); 
    } 
    catch (IOException e) { 
     e.printStackTrace(); 
    } 
+0

Những người khác không làm việc cho tôi, ngoại trừ trong IDE. Điều này đã làm, cảm ơn bạn. – Steve

+1

Có vẻ đẹp - nhưng chúng ta phải sử dụng mã tự thực hiện như vậy? Không có hỗ trợ trong Java để chuyển hướng STDERR vào STDOUT và sau đó để đọc sự kết hợp của chúng từ một dòng đầu vào? – SomethingSomething

Các vấn đề liên quan