2009-06-23 10 views
5

È possibile utilizzare NIO per elaborare lo stdout da un processo? Ho lavorato con java.io, ma questo è un esercizio per imparare un po 'di più su NIO e per esplorare la possibilità di migliorare le prestazioni.È possibile leggere il Process stdout InputStream in un ByteBuffer NIO?

In pratica, voglio eseguire il flusso di un grande volume di testo da stdout in un buffer il più velocemente possibile senza bloccare e quindi elaborare il contenuto di tale buffer in un secondo momento. Il problema è che non riesco a capire il giusto voodoo per farlo funzionare con NIO. Questo è dove mi trovo ora:

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

Lo StreamConsumer classe si presenta così:

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

Vuoi avere semplicemente tutto lo standard input in un buffer singolo byte in una volta? Conosci una lunghezza massima del flusso di input? –

+0

Mi piacerebbe leggerlo in un buffer tutto in una volta si, ma la lunghezza è sconosciuta; tipicamente nella gamma di 10 MB però. – Rob

risposta

5

Che ci crediate o no, penso che il canale di byte scrivibile che vuoi è

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

Quindi, al termine,

ostream.toByteArray() 

contengono s i byte da elaborare. Oppure, se si desidera un buffer di byte,

ByteBuffer.wrap(ostream.toByteArray()) 

non vedo qui come si ottiene l'uscita al di fuori del eseguibile, ma ho il sospetto il codice originale aveva questo. Altrimenti si potrebbe desiderare che lo sia un Callable<ByteBuffer>.

+1

Eccellente suggerimento per usare Callable. Non posso credere di averlo dimenticato. Questo ha funzionato come un fascino. – Rob

1

si potrebbe desiderare che lo StreamConsumer sia un chiamabile.

Un'altra opzione non bloccante da provare potrebbe essere l'utilizzo di Guable's ListenableFuture che offre callback di successo e fallimento senza interpretare errori personali.

4

Ho creato una libreria open source che consente l'I/O non bloccante tra i processi java e figlio. La libreria fornisce un modello di callback basato sugli eventi. Dipende dalla libreria JNA per utilizzare API native specifiche della piattaforma, come epoll su Linux, kqueue/kevent su MacOS X o Porte di completamento IO su Windows.

Il progetto si chiama NuProcess e può essere trovato qui:

https://github.com/brettwooldridge/NuProcess

Problemi correlati