2011-10-13 41 views
5

Tôi muốn lấy đầu ra từ lệnh shell đang chạy dài vì nó có sẵn thay vì chờ lệnh hoàn thành. Mã của tôi được chạy trong một thread mớiJava Runtime.exec() đầu ra không đồng bộ

Process proc = Runtime.getRuntime().exec("/opt/bin/longRunning"); 
InputStream in = proc.getInputStream(); 
int c; 
while((c = in.read()) != -1) { 
    MyStaticClass.stringBuilder.append(c); 
} 

Vấn đề ở đây là chương trình của tôi trong/opt/bin/longRunning phải hoàn thành trước khi InputStream được giao và đọc. Có cách nào tốt để làm điều này một cách không đồng bộ? Mục tiêu của tôi là một yêu cầu ajax sẽ trả về giá trị hiện tại MyStaticClass.stringBuilder.toString() mỗi giây hoặc lâu hơn.

Tôi bị kẹt trên Java 5, fyi.

Cảm ơn! W

+0

Cảm ơn tất cả! Apache Commons 'Exec là con đường tôi đã đi. @Paul Cager, bạn cũng cung cấp một ý tưởng tuyệt vời. Kịch bản đã được gọi là trong thực tế phát hiện rằng nó đã được đường ống và ngăn chặn. Tuy nhiên luồng mà bạn nhận được từ Runtime.exec được đồng bộ hóa, vì vậy nếu bạn cố gắng đọc nó, nó đang chặn. – wmarbut

Trả lời

7

Hãy thử với Apache Common Exec. Nó có khả năng thực hiện không đồng bộ một quá trình và sau đó "bơm" đầu ra cho một luồng. Kiểm tra Javadoc để biết thêm

1

Runtime.getRuntime(). Exec thực hiện không chờ lệnh chấm dứt, vì vậy bạn sẽ nhận được kết quả ngay lập tức. Có lẽ đầu ra đang được đệm bởi vì lệnh biết nó đang ghi vào một đường ống chứ không phải là một thiết bị đầu cuối?

1

Đặt đọc trong một chủ đề mới:

new Thread() { 
    public void run() { 
     InputStream in = proc.getInputStream(); 
     int c; 
     while((c = in.read()) != -1) { 
      MyStaticClass.stringBuilder.append(c); 
     } 
    } 
}.start(); 
+0

Tôi có thể là một chút daft ở đây, nhưng làm thế nào bạn sẽ nhận được biến c của bạn ra khỏi thread? Bên cạnh đó, không nên c là một chuỗi? –

2

Bạn viết chương trình mà bạn đang gọi điện thoại? Nếu vậy hãy thử xả đầu ra của bạn sau khi viết. Các văn bản có thể bị mắc kẹt trong một bộ đệm và không nhận được vào chương trình java của bạn.

tôi sử dụng mã này để làm điều này và nó hoạt động:

Runtime runtime = Runtime.getRuntime(); 
    Process proc = runtime.exec(command); 
    BufferedReader br = new BufferedReader(new InputStreamReader(proc.getInputStream())); 

    while (true) { 

     // enter a loop where we read what the program has to say and wait for it to finish 
     // read all the program has to say 
     while (br.ready()) { 
      String line = br.readLine(); 
      System.out.println("CMD: " + line); 
     } 

     try { 
      int exitCode = proc.exitValue(); 
      System.out.println("exit code: " + exitCode); 
      // if we get here then the process finished executing 
      break; 
     } catch (IllegalThreadStateException ex) { 
      // ignore 
     } 

     // wait 200ms and try again 
     Thread.sleep(200); 

    } 
+0

BufferedReader.ready() cũng bao gồm trạng thái của BufferedReader.readLine()? Tài liệu chỉ đề cập rằng ready() cho biết khi read() có thể được sử dụng, readLine() có thể là một vài hoạt động read(), do đó phương pháp này vẫn có thể chặn khi tôi hiểu nó. – bcause

+0

Bạn nói đúng, nó sẽ chặn và ở trong vòng lặp này cho đến khi quá trình con thoát ra. Điều này là đúng theo ý kiến ​​của tôi. Nếu bạn muốn làm điều gì đó khác trước khi chương trình này kết thúc chạy thì hãy đặt mã này vào một luồng riêng biệt và thực hiện công việc khác trong một luồng khác. Tôi không thấy một cách để làm cho InputStream trở về từ Process non-blocking như bạn có thể làm với các socket mạng. Trong trường hợp đó, nó sẽ ném một ngoại lệ hết thời gian chờ khi bạn cố gắng đọc từ luồng. –

0

Hãy thử:

try { 
     Process p = Runtime.getRuntime().exec("/opt/bin/longRunning"); 
     BufferedReader in = new BufferedReader( 
            new InputStreamReader(p.getInputStream())); 
     String line = null; 
     while ((line = in.readLine()) != null) { 
     System.out.println(line); } 
Các vấn đề liên quan