2011-10-03 17 views
7

Necesito un método java que leerá la salida del símbolo del sistema y lo almacenará en una cadena para leer en Java.Obtener salida de símbolo del sistema a cadena en Java

Esto es lo que tengo hasta ahora pero no está funcionando bien.

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() 

Creo que el problema es cuando intento cambiar la consulta a ser un comando que ejecutará HandBrakeCLI.exe. Al mirar mi sistema cuando el programa se está ejecutando (pero parece haberse detenido), me muestra que HandBrakeCLI.exe se está ejecutando bajo una ventana de cmd que se está ejecutando bajo mi IDE. Todo eso tiene sentido, pero el HandBrakeCLI.exe no se cierra, así que supongo que es por eso que no puedo leer el resultado como entrada a mi programa.

Entonces, después de ese fondo. Mi gran pregunta es esta: ¿cómo cierro HandBrakeCLI.exe una vez que ha terminado mi consulta para poder obtener su resultado? Solo para obtener información adicional, la única diferencia entre el método anterior y el método de escaneo de DVD que tengo para HandBrakeCLI es que la variable de consulta es diferente. Como en este ejemplo:

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' 

Ah, y por cierto, cuando corro que consulta en un símbolo del sistema regular, que hace exactamente lo que yo quiero que, dándome toda la salida que desesperadamente deseo!

Aquí está el problema original (no estoy seguro de cómo volver a presentar una pregunta):

He estado buscando por todas partes y no se puede resolver esto. No estoy seguro de que lo que encontré sea relevante para lo que quiero hacer. Aún no tengo muchos códigos, por lo que no haré demasiado para poner el código aquí y creo que esto debería ser bastante simple, así que voy a dar algunas capturas de pantalla aquí. Así que aquí está mi tarea:

  1. Buscar en la carpeta que está lleno de carpetas de DVD rasgados (VIDEO_TS carpetas con archivos VOB etc.) y almacenar estos nombres de las carpetas como el título del DVD.

  2. Escanee cada carpeta con HandBrakeCLI y almacene la salida en una cadena.

  3. Regesta la cadena para identificar cada título, capítulo e idioma.

  4. generar consultas para dar vuelta a HandBrakeCLI para codificar mayor cada idioma en cada capítulo en cada título para cada DVD (se puede ver por qué quiero para automatizar este!)

  5. almacenar estas consultas en un archivo *. bat archivo

¡La única parte de la que no estoy seguro es el paso 2! Puedo hacer todo lo demás con bastante facilidad. He leído mucho sobre OutputStreams, pero parece que no puedo entender cómo funciona. Realmente solo necesito obtener el resultado de una cadena que pueda volver a generar para obtener las cosas que necesito.Estas son las capturas de pantalla de lo que necesito para la entrada y lo que necesito para despojar de la salida:

entrada a HandBrakeCLI:

enter image description here

salida para escanear:

enter image description here

Respuesta

5

En primer lugar necesita una forma de no bloqueo para leer desde Standard.out y Standard.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(); 
    } 
} 

Luego hay que atar esta clase en los respectivos objetos InputStream y OutputStream.

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); 
    } 

Esto es más o menos la placa de la caldera que utilizo cuando necesito Runtime.exec() nada en Java.

una forma más avanzada sería utilizar FutureTask y Callable o al menos Runnable en lugar de extender directamente Thread que no es la mejor práctica.

NOTA:

Los @Nonnull anotaciones están en la biblioteca JSR305. Si está utilizando Maven, y está utilizando Maven, ¿no es así? Solo agregue esta dependencia a su pom.xml.

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

Jarrod, gracias por la respuesta rápida! ¡Trataré de implementar esto de inmediato y te haré saber cómo funciona! – kentcdodds

+0

¡Perfecto! No estoy exactamente seguro de cómo funciona. Pero lo analizaré un poco para descubrirlo. Pero sí, funcionó como un encanto! ¡Ahora solo tengo que volver a expresar todo eso! De todos modos, ¡muchas gracias por tu ayuda! Ah, y no estoy seguro de lo que es Maven. Mi IDE es Netbeans. No necesité agregar el material . ¡Gracias de nuevo! – kentcdodds

1

Suponiendo que usa Runtime.exec() para comenzar su proceso externo, dándole un objeto Process, hay tres métodos relevantes sobre ese objeto: getOutputStream(), getInputStream() y getErrorStream().

Creo que es fácil confundirse con esto: probablemente esté pensando que desea ver el resultado del proceso, por lo que una "secuencia de salida" es lo que desea. Pero lo que necesita recordar es que el nombre de estos objetos es desde la perspectiva del código de Java: un OutputStream es para que Java escriba la salida, mientras que un InputStream es para que Java pueda leer la entrada. El resultado de su proceso externo es, desde la perspectiva de Java, la entrada.

Entonces debería usar getInputStream() y llamar a los métodos apropiados en el InputStream devuelto por este para leer la salida. También puede usar getErrorStream() para asegurarse de que no le falta nada porque está escrito en un error estándar.

+0

Gracias por la aclaración! Eso fue un poco confuso El problema al que me enfrento ahora es que, en lugar de imprimir los resultados de la consulta (como se ve en mi segunda captura de pantalla), está imprimiendo la consulta en sí. Hay mucho contenido en el código para agregar a un comentario aquí, así que aquí hay un enlace a un documento collabedit: http: // collabedit.com/5r384 – kentcdodds

+0

Una cuestión, creo, es que 'exec()' espera un ejecutable real: un archivo de proceso por lotes no es un programa ejecutable, es una serie de comandos que debe ejecutar el shell de Windows. Consulte http://stackoverflow.com/questions/615948/how-doi-i-run-a-batch-file-from- my-java-application. –

+0

¡Nos estamos acercando mucho! Así que ahora mi problema es que mi objeto de memoria intermedia es nulo. No estoy seguro por qué. Actualicé el código en el documento collabedit. Notarás que coloque println alrededor del comandoResult porque es donde el código hace una pausa, y commandResult.readLine() = null cuando debería ser igual a la primera línea de entrada (o al menos, eso es lo que estoy buscando). ¡Gracias de nuevo por la ayuda! http://collabedit.com/5r384 – kentcdodds

5

Este ejemplo completo programa Java se ejecuta el comando 'dir' (listado de directorio) en la línea de comandos y saca el resultado en una cadena y lo imprime en la consola.

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(){ } 
} 

En Windows, esto es el resultado consigo

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 para publicar otra solución viable para las generaciones venideras. – kentcdodds

Cuestiones relacionadas