2013-05-23 28 views
38

Tôi đang sử dụng đoạn mã sau để bắt đầu một trình xây dựng quy trình. Tôi muốn biết làm thế nào tôi có thể chuyển hướng đầu ra của nó đến một Chuỗi. Làm thế nào để chuyển hướng đầu ra của Trình Xây dựng Quy trình thành một chuỗi?

ProcessBuilder pb = new ProcessBuilder(System.getProperty("user.dir")+"/src/generate_list.sh", filename); 
Process p = pb.start(); 

tôi đã cố gắng sử dụng ByteArrayOutputStream nhưng nó dường như không làm việc.

+0

cách bạn sử dụng 'ByteArrayOutputStream'? – fGo

+0

'Nó dường như không hoạt động' không phải là một mô tả vấn đề. 'ProcessBuilder' không có luồng, nhưng' Process' thực hiện. Bạn không bắt đầu một 'ProcessBuilder', bạn đang sử dụng nó để tạo * một' Process', và sau đó bắt đầu * đó. * Hãy chính xác. – EJP

Trả lời

45

Đọc từ số InputStream. Bạn có thể thêm đầu ra cho một StringBuilder:

BufferedReader reader = 
       new BufferedReader(new InputStreamReader(process.getInputStream())); 
StringBuilder builder = new StringBuilder(); 
String line = null; 
while ((line = reader.readLine()) != null) { 
    builder.append(line); 
    builder.append(System.getProperty("line.separator")); 
} 
String result = builder.toString(); 
+2

Bạn có thể muốn thêm cách nhận luồng lỗi hoặc cả hai. – Fabian

+4

@Fabian Điều này có thể dễ dàng được thực hiện bằng cách sử dụng 'processBuilder.inheritIO() ' – Reimeus

+0

@Reimeus loại bỏ ký tự cuối cùng của dòng và thay thế bằng ký tự hiện tại, có thể khác nhau. – neuralmer

8

Bạn có thể làm điều gì đó như thế này:

private static BufferedReader getOutput(Process p) { 
    return new BufferedReader(new InputStreamReader(p.getInputStream())); 
} 

private static BufferedReader getError(Process p) { 
    return new BufferedReader(new InputStreamReader(p.getErrorStream())); 
} 
... 
Process p = Runtime.getRuntime().exec(commande); 
BufferedReader output = getOutput(p); 
BufferedReader error = getError(p); 
String ligne = ""; 

while ((ligne = output.readLine()) != null) { 
    System.out.println(ligne); 
} 

while ((ligne = error.readLine()) != null) { 
System.out.println(ligne); 
} 
+3

Điều này có thể bị treo trong trường hợp quy trình ghi số lượng dữ liệu lớn hơn vào stderr - xem http://stackoverflow.com/questions/16983372/why-does-process-hang-if-the-parent-does-not-consume-stdout -stderr-in-java –

1

Chỉ cần thêm .inheritIO(); vào dòng quá trình xây dựng.

IE:

ProcessBuilder pb = new ProcessBuilder(script.sh).inheritIO();

+3

Vì vậy, làm thế nào để có được chuỗi đầu ra lệnh? –

+1

@MarkoBonaci xem câu trả lời được chấp nhận cho điều đó. Bạn cần sử dụng bộ đệm BufferedReader = new BufferedReader (new InputStreamReader (process.getInputStream())); và sau đó xây dựng một StringBuilder với đầu ra. –

+0

Lưu ý rằng phương thức .inheritIO() là dành cho java 7 và cao hơn –

2

Đối với Java 7 và 8 này nên làm việc:

private String getInputAsString(InputStream is) 
{ 
    try(java.util.Scanner s = new java.util.Scanner(is)) 
    { 
     return s.useDelimiter("\\A").hasNext() ? s.next() : ""; 
    } 
} 

Sau đó, trong mã của bạn, làm điều này:

String stdOut = getInputAsString(p.getInputStream()); 
String stdErr = getInputAsString(p.getErrorStream()); 

Tôi không biết xấu hổ lấy trộm đó từ: How to redirect Process Builder's output to a string?

1

Trong java 8 có một đường đẹp() dòng bạn có thể kết hợp với string.Join và System.lineSeparator():

try (BufferedReader outReader = new BufferedReader(new InputStreamReader(p.getInputStream())) 
    { 
     return String.join(System.lineSeparator(), outReader.lines().collect(toList())); 
     \\ OR using jOOλ if you like reduced verbosity 
     return Seq.seq(outReader.lines()).toString(System.lineSeparator()) 
    } 
13

Sử dụng Apache Commons IOUtils bạn có thể làm điều đó trong một dòng:

ProcessBuilder pb = new ProcessBuilder("pwd"); 
String output = IOUtils.toString(pb.start().getInputStream()); 
+0

Luồng vẫn cần được đóng sau đó, phải không? – jbird

+0

Không chắc chắn. Tôi đã không nhìn thấy bất kỳ ví dụ ProcessBuilder mà đóng InputStream. Một câu trả lời về Quy trình nói rằng bạn vẫn nên đóng luồng .... http://stackoverflow.com/questions/7097697/properly-closing-java-process-inputstream-from-getinputstream#answer-7100172 – Daniel

2

Sau khi cố gắng xử lý các trường hợp khác nhau (xử lý cả stderr và stdout và không chặn bất kỳ trường hợp nào, chấm dứt quy trình sau khi hết thời gian chờ, thoát dấu gạch chéo, dấu ngoặc kép, ký tự đặc biệt, dấu cách, ....) Apache Commons Exechttps://commons.apache.org/proper/commons-exec/tutorial.html dường như đang làm tất cả những điều này khá tốt.

Tôi khuyên mọi người cần gọi quá trình bên ngoài trong java để sử dụng thư viện Apache Commons Exec thay vì phát minh lại nó.

+1

Cảm ơn bạn rất nhiều . Tôi đã cố gắng để thực hiện chương trình wkhtmltopdf với các đối số bằng cách sử dụng ProcessBuilder. Đó là ok trong Windows nhưng trong máy chủ Linux nó không thành công và tôi đã không thể có được đầu ra với BufferedReader. Tuy nhiên mọi thứ đều dễ dàng với commons-exec và nó hoạt động tốt trong cả hai hệ điều hành. – jmoran

1

Java 8 Ví dụ:

public static String runCommandForOutput(List<String> params) { 
    ProcessBuilder pb = new ProcessBuilder(params); 
    Process p; 
    String result = ""; 
    try { 
     p = pb.start(); 
     final BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream())); 

     StringJoiner sj = new StringJoiner(System.getProperty("line.separator")); 
     reader.lines().iterator().forEachRemaining(sj::add); 
     result = sj.toString(); 

     p.waitFor(); 
     p.destroy(); 
    } catch (Exception e) { 
     e.printStackTrace(); 
    } 
    return result; 
} 

Cách sử dụng:

List<String> params = Arrays.asList("/bin/sh", "-c", "cat /proc/cpuinfo"); 
String result = runCommandForOutput(params); 

tôi sử dụng mã này chính xác và nó hoạt động tốt cho kết quả dòng đơn hoặc nhiều. Bạn cũng có thể thêm trình xử lý luồng lỗi.