2012-01-05 51 views
9

Có thể truyền đầu ra của một tiến trình được tạo bởi ProcessBuilder đến một tiến trình khác được tạo bởi ProcessBuilder khác không? Ví dụ: nếu tôi đang cố thực hiện lệnh shell này:đầu ra đường ống của ProcessBuilder đến một ProcessBuilder khác

ls | grep build.xml 

Tôi nên làm điều đó với ProcessBuilder như thế nào?

như @erdinc đề nghị, tôi đã cố gắng này:

Process process = Runtime.getRuntime().exec("ls"); 
InputStream is = process.getInputStream(); 
byte[] buf = new byte[1000]; 
is.read(buf); 
String parameter = new String(buf); 
System.out.println("grep build " + parameter); 

Process proc2 = Runtime.getRuntime().exec("grep build " + parameter); 
InputStream is2 = proc2.getInputStream(); 
byte[] buf2 = new byte[1000]; 
is2.read(buf2); 
String result = new String(buf2); 
System.out.println("proc2 result: " + result); 

nhưng nó tạo ra kết quả khác nhau so với khi tôi chạy kịch bản trực tiếp trong vỏ. Tôi đã làm sai ở đâu?

Giải quyết: Vui lòng xem giải pháp Philipp Wendler

Trả lời

6

Vấn đề với giải pháp bạn có là nó chỉ đọc 1000 byte đầu tiên từ đầu ra của ls và chuyển chúng đến grep. Vì bạn không biết số lượng đầu ra từ ls trước đây, bạn cần phải đọc nó một cách lặp đi lặp lại cho đến khi nó hết.

Đây là một giải pháp sử dụng BufferedReader, mà sẽ gửi cho mỗi dòng sản lượng để grep:

Process lsProcess = Runtime.getRuntime().exec("ls"); 
BufferedReader lsOutput = new BufferedReader(new InputStreamReader(lsProcess.getInputStream())); 
Process grepProcess = Runtime.getRuntime().exec("grep build.xml"); 
BufferedWriter grepInput = new BufferedWriter(new OutputStreamWriter(grepProcess.getOutputStream())); 

String line; 
// read each line from ls until there are no more 
while ((line = lsOutput.readLine()) != null) { 
    // and send them to grep 
    grepInput.write(line); 
    grepInput.newLine(); 
} 

// send end-of-file signal to grep so it will terminate itself 
grepInput.close(); 

Tất nhiên bạn cần phải thêm các lỗi xử lý ở đây thích hợp. Bạn có thể bỏ qua Reader và Writer và chuyển các mảng byte[] trực tiếp từ đầu vào đến luồng đầu ra nếu giải pháp này quá chậm.

Tuy nhiên, giải pháp tốt hơn nhiều là không sử dụng ls và grep để tìm kiếm tệp trong hệ thống tệp nhưng phải sử dụng API Java thích hợp. Ví dụ: nếu bạn tạo đối tượng File cho thư mục bạn quan tâm, bạn có thể sử dụng các phương thức listFiles khác nhau để liệt kê tất cả các tệp trong thư mục này. Phương pháp này dễ dàng hơn nhiều, di động, ít bị lỗi và có thể nhanh hơn.

+0

giải pháp của bạn hoạt động! cảm ơn bạn Philipp: D Tôi thực sự sẽ sử dụng mã này để gọi một số ứng dụng bên ngoài như chasen và moses (công cụ dịch máy). Các ls | Ví dụ grep có nghĩa là chỉ để đơn giản hóa câu hỏi, nhưng cảm ơn cho đề nghị: D Tôi sẽ đánh dấu câu hỏi được giải quyết và upvote giải pháp của bạn. – ndriks

0

Bạn có thể sử dụng phương thức getInputStream hơn là tham số thứ hai. Mã ví dụ;

 process = Runtime.getRuntime().exec("ls"); 
     InputStream is = process.getInputStream(); 
     byte[] buf = new byte[1000]; 
     is.read(buf); 
     String parameter = new String(buf); 
     System.out.println(parameter); 
     Runtime.getRuntime().exec("grep build.xml " + parameter); 
+0

nhưng cách chuyển luồng đầu vào "ls" vào quy trình "grep"? Tôi dường như không thể tìm phương thức setInputStream trong Process. Ngoài ra nó có thể được thực hiện với ProcessBuilder? – ndriks

+0

Tôi đã thử giải pháp của bạn @erdinc, nhưng nó tạo ra kết quả khác nhau so sánh với việc chạy lệnh trực tiếp trong trình bao. Tôi đã chỉnh sửa câu hỏi để hiển thị những gì tôi đã làm. FYI, tôi không cố gắng để chạy grep với ls kết quả là tham số, nhưng tôi đang cố gắng để ống kết quả của ls để quá trình grep. – ndriks

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