2009-06-23 8 views
5

¿Es posible usar NIO para procesar el stdout de un proceso? Lo tengo trabajando con java.io, pero esto es algo así como un ejercicio para aprender un poco más sobre NIO y explorar la posibilidad de mejoras en el rendimiento.¿Es posible leer el proceso stdout InputStream en un NIO ByteBuffer?

Básicamente quiero transmitir un gran volumen de texto de stdout a un búfer lo más rápido posible sin bloquear, y luego procesar el contenido de ese búfer más tarde. El problema es que parece que no puedo encontrar el vudú adecuado para que funcione con NIO. Aquí es donde estoy ahora:

ProcessBuilder pb = new ProcessBuilder(...); 
Process p = pb.start(); 
stdout = new StreamConsumer(p.getInputStream()); 
new Thread(stdout).start(); 
// other stuff omitted for brevity 

El StreamConsumer clase tiene este aspecto:

class StreamConsumer implements Runnable 
{ 
    private InputStream is; 

    public StreamConsumer(InputStream is) 
    { 
    this.is = is; 
    } 

    public void run() 
    { 
    try 
    { 
     ReadableByteChannel source = Channels.newChannel(is); 

     // Is it possible get a channel to a ByteBuffer 
     // or MappedByteBuffer here? 
     WritableByteChannel destination = ??; 
     ByteBuffer buffer = ByteBuffer.allocateDirect(128 * 1024); 

     while (source.read(buffer) != -1) 
     { 
     buffer.flip(); 
     while (buffer.hasRemaining()) 
     { 
      destination.write(buffer); 
     } 
     buffer.clear(); 
     } 

     source.close(); 
     destination.close(); 
    } 
    catch (IOException e) 
    { 
     e.printStackTrace(); 
    } 
    } 
} 
+0

es lo que quieres simplemente tener toda la entrada estándar en una sola memoria intermedia de bytes a la vez? ¿Conoces la duración máxima de la secuencia de entrada? –

+0

Me gustaría leerlo en un buffer de una vez sí, pero la longitud es desconocida; típicamente en el rango de 10 MB sin embargo. – Rob

Respuesta

5

creas o no, creo que el canal de bytes grabable que desea es

ByteArrayOutputStream ostream = new ByteArrayOutputStream(<some large number>); 
WritableByteChannel destination = Channels.newChannel(ostream); 

Luego cuando termine

ostream.toByteArray() 

contienen s los bytes a procesar. O, si quieres una memoria intermedia de bytes,

ByteBuffer.wrap(ostream.toByteArray()) 

no veo aquí cómo se obtiene la salida fuera del ejecutable, pero sospecho que su código original tenía eso. De lo contrario, es posible que desee que el StreamConsumer sea un Callable<ByteBuffer>.

+1

Excelente sugerencia para usar Llamable. No puedo creer que me haya olvidado de eso. Funcionó como por arte de magia. – Rob

1

es posible que desee que el StreamConsumer sea un llamamiento.

Otra opción que no debe ser bloqueada para intentarlo es utilizar el ListenableFuture de Guava, que le proporciona devoluciones de llamada exitosas y fallidas sin interpretar errores propios.

4

He creado una biblioteca de código abierto que permite E/S sin bloqueo entre los procesos de java y su hijo. La biblioteca proporciona un modelo de devolución de llamada por evento. Depende de la biblioteca JNA utilizar API nativas específicas de la plataforma, como epoll en Linux, kqueue/kevent en MacOS X o IO Completion Ports en Windows.

El proyecto se llama NuProcess y se puede encontrar aquí:

https://github.com/brettwooldridge/NuProcess

Cuestiones relacionadas