2011-10-03 69 views
7

Tôi cần một phương thức java sẽ đọc đầu ra dấu nhắc lệnh và lưu nó vào một Chuỗi để được đọc vào Java.Nhận Đầu ra Dấu nhắc Lệnh tới Chuỗi Trong Java

Đây là những gì tôi có cho đến nay nhưng không hoạt động chính xác.

public void testGetOutput() { 
    System.out.println("\n\n****This is the testGetOutput Method!****"); 
    String s = null; 
    String query = "dir " + this.desktop; 
    try { 
     Runtime runtime = Runtime.getRuntime(); 
     InputStream input = runtime.exec("cmd /c " + query).getInputStream(); 
     BufferedInputStream buffer = new BufferedInputStream(input); 
     BufferedReader commandResult = new BufferedReader(new InputStreamReader(buffer)); 
     String line = ""; 
     try { 
      while ((line = commandResult.readLine()) != null) { 
       s += line + "\n"; 
      } 
     } catch (Exception e) { 
      e.printStackTrace(); 
     } 
     System.out.println(s); 
    } catch (Exception e) { 
     e.printStackTrace(); 
    } 
}//end testGetOutput() 

Tôi nghĩ rằng vấn đề là khi tôi cố gắng thay đổi truy vấn thành lệnh sẽ thực thi HandBrakeCLI.exe. Nhìn vào hệ thống của tôi khi chương trình đang chạy (nhưng dường như đã tạm dừng), nó cho tôi thấy rằng HandBrakeCLI.exe đang chạy dưới một cửa sổ cmd đang được chạy theo IDE của tôi. Tất cả điều đó có ý nghĩa, nhưng HandBrakeCLI.exe không thoát, vì vậy tôi đoán đó là lý do tại sao tôi không thể đọc đầu ra làm đầu vào cho chương trình của mình.

Vì vậy, sau nền đó. Câu hỏi lớn của tôi là: Làm thế nào để có được HandBrakeCLI.exe để đóng sau khi nó kết thúc với truy vấn của tôi vì vậy tôi có thể nhận được đầu ra của nó? Chỉ cần thêm thông tin, sự khác biệt duy nhất giữa phương pháp trên và phương pháp quét DVD tôi có cho HandBrakeCLI là biến truy vấn khác nhau. Giống như ví dụ sau:

String query = "C:\Users\Kent\Desktop\HBCLI\HandBrakeCLI -t --scan -i "C:\Users\Kent\Desktop\General Conference DVDs\Sources\174th October 2004\DVD 1"; //this is actually a variable in the DVD object, but here's an example' 

Oh, và bằng cách này, khi tôi chạy truy vấn rằng trong một dấu nhắc lệnh thường xuyên, nó thực hiện chính xác những gì tôi muốn nó, đem lại cho tôi tất cả các đầu ra tôi tuyệt vọng mong muốn!

Đây là vấn đề gốc (Tôi không chắc chắn làm thế nào để gửi lại một câu hỏi):

Tôi đã tìm kiếm khắp nơi và không thể hình này ra. Tôi không chắc chắn những gì tôi đã tìm thấy thậm chí có liên quan đến những gì tôi muốn làm. Tôi không có nhiều mã cho nó, vì vậy nó sẽ không làm gì nhiều để đặt mã ở đây và tôi nghĩ rằng điều này nên khá đơn giản, vì vậy tôi sẽ cung cấp cho một số ảnh chụp màn hình ở đây. Vì vậy, đây là nhiệm vụ của tôi:

  1. thư mục Scan được đầy đủ các thư mục DVD xé (VIDEO_TS thư mục với file VOB vv) và lưu trữ các tên thư mục như tiêu đề của DVD.

  2. Quét từng thư mục bằng HandBrakeCLI và lưu đầu ra vào chuỗi.

  3. Chỉnh sửa chuỗi để xác định từng tiêu đề, chương và ngôn ngữ.

  4. Tạo truy vấn để trả lại cho HandBrakeCLI để mã hóa số lượng lớn mỗi ngôn ngữ trong mỗi chương trong mỗi tiêu đề cho mỗi DVD (bạn có thể thấy lý do tại sao tôi muốn tự động hoá này!)

  5. Lưu trữ các truy vấn trong một *. bat file

Phần duy nhất tôi không chắc chắn là bước 2! Tôi có thể làm mọi thứ khác khá dễ dàng. Tôi đã đọc rất nhiều về OutputStreams, nhưng tôi dường như không thể hiểu nó hoạt động như thế nào. Tôi thực sự chỉ cần để có được đầu ra cho một chuỗi mà tôi có thể regex để có được những thứ tôi cần.Dưới đây là ảnh chụp màn hình của những gì tôi cần phải đầu vào và những gì tôi cần phải lột từ đầu ra:

Input để HandBrakeCLI:

enter image description here

Output để quét:

enter image description here

Trả lời

5

Trước tiên, bạn cần một cách non-blocking để đọc từ Standard.outStandard.err

private class ProcessResultReader extends Thread 
{ 
    final InputStream is; 
    final String type; 
    final StringBuilder sb; 

    ProcessResultReader(@Nonnull final InputStream is, @Nonnull String type) 
    { 
     this.is = is; 
     this.type = type; 
     this.sb = new StringBuilder(); 
    } 

    public void run() 
    { 
     try 
     { 
      final InputStreamReader isr = new InputStreamReader(is); 
      final BufferedReader br = new BufferedReader(isr); 
      String line = null; 
      while ((line = br.readLine()) != null) 
      { 
       this.sb.append(line).append("\n"); 
      } 
     } 
     catch (final IOException ioe) 
     { 
      System.err.println(ioe.getMessage()); 
      throw new RuntimeException(ioe); 
     } 
    } 

    @Override 
    public String toString() 
    { 
     return this.sb.toString(); 
    } 
} 

Sau đó, bạn cần phải buộc lớp này vào tương ứng InputStreamOutputStream đối tượng.

try 
    { 
     final Process p = Runtime.getRuntime().exec(String.format("cmd /c %s", query)); 
     final ProcessResultReader stderr = new ProcessResultReader(p.getErrorStream(), "STDERR"); 
     final ProcessResultReader stdout = new ProcessResultReader(p.getInputStream(), "STDOUT"); 
     stderr.start(); 
     stdout.start(); 
     final int exitValue = p.waitFor(); 
     if (exitValue == 0) 
     { 
      System.out.print(stdout.toString()); 
     } 
     else 
     { 
      System.err.print(stderr.toString()); 
     } 
    } 
    catch (final IOException e) 
    { 
     throw new RuntimeException(e); 
    } 
    catch (final InterruptedException e) 
    { 
     throw new RuntimeException(e); 
    } 

Đây là loại nồi hơi tôi sử dụng khi cần Runtime.exec() bất kỳ thứ gì trong Java.

Cách nâng cao hơn sẽ là sử dụng FutureTaskCallable hoặc ít nhất Runnable thay vì mở rộng trực tiếp Thread không phải là phương pháp hay nhất.

LƯU Ý:

Các @Nonnull chú thích trong thư viện JSR305. Nếu bạn đang sử dụng Maven và bạn đang sử dụng Maven thì không phải bạn, chỉ cần thêm phụ thuộc này vào số pom.xml của bạn.

<dependency> 
    <groupId>com.google.code.findbugs</groupId> 
    <artifactId>jsr305</artifactId> 
    <version>1.3.9</version> 
</dependency> 
+0

Jarrod, cảm ơn bạn đã phản hồi nhanh! Tôi sẽ cố gắng thực hiện điều này ngay lập tức và cho bạn biết làm thế nào nó đi! – kentcdodds

+0

Hoàn hảo! Tôi không chắc chắn nó hoạt động như thế nào. Nhưng tôi sẽ xem xét nó một chút để tìm ra. Nhưng vâng, nó hoạt động như một sự quyến rũ! Bây giờ tôi chỉ cần phải regex tất cả những thứ đó! Dù sao, cảm ơn một tấn cho sự giúp đỡ của bạn! Ồ, và tôi không chắc Maven là gì. IDE của tôi là Netbeans. Tôi không cần phải thêm các công cụ . Cảm ơn một lần nữa! – kentcdodds

1

Giả sử bạn sử dụng Runtime.exec() để bắt đầu quy trình bên ngoài của mình, cung cấp cho bạn đối tượng Process, có ba phương pháp có liên quan trên đối tượng đó: getOutputStream(), getInputStream()getErrorStream().

Tôi nghĩ rất dễ nhầm lẫn về những điều này - bạn có thể nghĩ rằng bạn muốn xem kết quả của quá trình, do đó, "luồng đầu ra" là những gì bạn muốn. Nhưng điều bạn cần nhớ là việc đặt tên của các đối tượng này là từ quan điểm của mã Java - một OutputStream là dành cho Java để ghi đầu ra, trong khi một InputStream là dành cho Java để đọc đầu vào từ đó. Đầu ra của quá trình bên ngoài của bạn là, từ quan điểm của Java, đầu vào.

Vì vậy, bạn sẽ sử dụng getInputStream() và gọi phương thức thích hợp trên InputStream được trả lại để đọc đầu ra. Bạn cũng có thể muốn sử dụng getErrorStream() để đảm bảo rằng bạn không thiếu bất kỳ thứ gì vì nó được ghi vào lỗi chuẩn.

+0

Cảm ơn bạn đã làm rõ! Đó là một chút bối rối. Vấn đề tôi đang phải đối mặt bây giờ là thay vì in kết quả của truy vấn (như được thấy trong ảnh chụp màn hình thứ hai của tôi), nó in chính truy vấn đó. Có quá nhiều nội dung trong mã để thêm vào nhận xét ở đây, vì vậy, đây là liên kết tới tài liệu cộng tác: http: // cộng tác.com/5r384 – kentcdodds

+0

Một vấn đề, tôi nghĩ, là 'exec()' mong đợi một tệp thực thi thực tế - một tệp bó không phải là một chương trình thực thi, nó là một chuỗi lệnh được thực thi bởi vỏ Windows. Xem http://stackoverflow.com/questions/615948/how-do-i-run-a-batch-file-from-my-java-application. –

+0

Chúng tôi đang thực sự gần gũi! Vì vậy, bây giờ vấn đề của tôi là đối tượng đọc đệm của tôi là null. Tôi cung không chăc tại sao. Tôi đã cập nhật mã trên tài liệu cộng tác. Bạn sẽ nhận thấy tôi đặt println xung quanh commandResult bởi vì đó là nơi mã tạm dừng, và commandResult.readLine() = null khi nó phải bằng dòng đầu vào đầu tiên (hoặc ít nhất, đó là những gì tôi đang tìm kiếm). Cảm ơn một lần nữa vì sự giúp đỡ! http://collabedit.com/5r384 – kentcdodds

5

đầy đủ chương trình Java Ví dụ này chạy lệnh 'dir' (danh sách thư mục) trên dòng lệnh và kéo kết quả vào một String và in nó trên bàn điều khiển.

import java.io.BufferedReader; 
import java.io.IOException; 
import java.io.InputStream; 
import java.io.InputStreamReader; 

public class X { 
    public static void main(String[] args) { 
     try{ 
      String command = "dir"; 
      String s = get_commandline_results(command); 
      System.out.println(s); 
     } 
     catch(Exception e){ 
      e.printStackTrace(); 
     } 
     System.out.println("done"); 
    } 

    public static String get_commandline_results(String cmd) 
     throws IOException, InterruptedException, IllegalCommandException{ 

     //Do not remove the authorizedCommand method. Be prepared 
     //to lose your hard drive if you have not white-listed the 
     //commands that can run. 
     if (!authorizedCommand(cmd)) 
      throw new IllegalCommandException(); 

     String result = ""; 
     final Process p = Runtime.getRuntime(). 
      exec(String.format("cmd /c %s", cmd)); 
     final ProcessResultReader stderr = new ProcessResultReader(
       p.getErrorStream(), "STDERR"); 
     final ProcessResultReader stdout = new ProcessResultReader(
       p.getInputStream(), "STDOUT"); 
     stderr.start(); 
     stdout.start(); 
     final int exitValue = p.waitFor(); 
     if (exitValue == 0){ 
      result = stdout.toString(); 
     } 
     else{ 
      result = stderr.toString(); 
     } 
     return result; 
    } 
    public static boolean authorizedCommand(String cmd){ 
     //Do not allow any command to be run except for the ones 
     //that we have pre-approved here. This lessens the 
     //likelihood that fat fingers will wreck your computer. 
     if (cmd.equals("dir")) 
      return true; 
     //add the commands you want to authorize here. 

     return false; 
    } 
} 

class ProcessResultReader extends Thread{ 
    final InputStream is; 
    final String type; 
    final StringBuilder sb; 

    ProcessResultReader(final InputStream is, String type){ 
     this.is = is; 
     this.type = type; 
     this.sb = new StringBuilder(); 
    } 

    public void run() 
    { 
     try{ 
      final InputStreamReader isr = new InputStreamReader(is); 
      final BufferedReader br = new BufferedReader(isr); 
      String line = null; 
      while ((line = br.readLine()) != null) 
      { 
       this.sb.append(line).append("\n"); 
      } 
     } 
     catch (final IOException ioe) 
     { 
      System.err.println(ioe.getMessage()); 
      throw new RuntimeException(ioe); 
     } 
    } 
    @Override 
    public String toString() 
    { 
     return this.sb.toString(); 
    } 
} 
class IllegalCommandException extends Exception{ 
    private static final long serialVersionUID = 1L; 
    public IllegalCommandException(){ } 
} 

Trên Windows, đây là kết quả tôi nhận được

Directory of D:\projects\eric\eclipseworkspace\testing2 
07/05/2012 01:06 PM <DIR>   . 
07/05/2012 01:06 PM <DIR>   .. 
06/05/2012 11:11 AM    301 .classpath 
06/05/2012 11:11 AM    384 .project 
06/05/2012 11:11 AM <DIR>   .settings 
07/05/2012 01:42 PM <DIR>   bin 
06/05/2012 11:11 AM <DIR>   src 
07/05/2012 01:06 PM    2,285 usernames.txt 
       3 File(s)   2,970 bytes 
       5 Dir(s) 45,884,035,072 bytes free 

done 
+0

+1 để đăng một giải pháp khả thi khác cho các thế hệ sắp tới. – kentcdodds

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