2010-04-17 9 views
2

Je souhaite envoyer un fichier contenu dans une archive ZIP décompressé à un programme externe pour le décoder davantage et lire le résultat dans Java.Données de tuyau d'InputStream à OutputStream en Java

ZipInputStream zis = new ZipInputStream(new FileInputStream(ZIPPATH)); 
Process decoder = new ProcessBuilder(DECODER).start(); 
??? 
BufferedReader br = new BufferedReader(new InputStreamReader(
     decoder.getInputStream(),"us-ascii")); 
for (String line = br.readLine(); line!=null; line = br.readLine()) { 
    ... 
} 

Que dois-je mettre en ??? pour tuyau le contenu zis au decoder.getOutputStream()? Je suppose qu'un thread dédié est nécessaire, car le processus de décodage peut bloquer lorsque sa sortie n'est pas consommée.

+0

Le décodage Zip n'est pas très coûteux - le surcoût du déchargement de l'unzip vers un autre processus est probablement plus que juste le décompresser localement. java.util.zip.Inflater fera tout le travail pour vous. –

+0

J'ai clarifié mon message qui était apparemment un peu trompeur. Le décodeur est censé faire autre chose que décompresser. – Wangnick

Répondre

3

Oui, un thread est nécessaire (ou vous attendez/bloquez jusqu'à la fin de la copie) pour copier l'InputStream dans le OutputStream. Vérifiez la classe org.apache.commons.net.io.Util pour plusieurs méthodes d'assistance pour copier les données.

+0

Eh bien, copyStream de org.apache.commons.net.io.Util n'est pas enfilé, donc la question est toujours là ... – Wangnick

+0

@Wangnick: Comme je l'ai dit, vous avez besoin d'un fil. La méthode 'copyStream' est juste une méthode d'aide, vous devez toujours le mettre dans un objet' Thread'/'Runnable'. – Progman

+0

Oui, je le sais, voir la question originale. Malheureusement, ce n'est pas aussi simple que vous l'avez indiqué ... – Wangnick

-1

Ok, je suis arrivé en ce qui suit:

public class CopyStream extends Thread { 
    static final int BUFFERSIZE = 10 * 1024; 
    InputStream input; OutputStream output; 
    boolean closeInputOnExit, closeOutputOnExit, flushOutputOnWrite; 
    public IOException ex; 
    public CopyStream (InputStream input, boolean closeInputOnExit, OutputStream output, boolean closeOutputOnExit, 
      boolean flushOutputOnWrite) { 
     super("CopyStream"); 
     this.input = input; this.closeInputOnExit = closeInputOnExit; 
     this.output = output; this.closeOutputOnExit = closeOutputOnExit; 
     this.flushOutputOnWrite = flushOutputOnWrite; 
     start(); 
    } 
    public void run() { 
     try { 
      byte[] buffer = new byte[BUFFERSIZE]; 
      for (int bytes = input.read(buffer); bytes>=0; bytes = input.read(buffer)) { 
       output.write(buffer,0,bytes); 
       if (flushOutputOnWrite) output.flush(); 
      } 
     } catch (IOException ex) { 
      this.ex = ex; 
     } finally { 
      if (closeInputOnExit) { 
       try { 
        input.close(); 
       } catch (IOException ex) { 
        if (this.ex==null) this.ex = ex; 
       } 
      } 
      if (closeOutputOnExit) { 
       try { 
        output.close(); 
       } catch (IOException ex) { 
        if (this.ex==null) this.ex = ex; 
       } 
      } 
     } 
    } 
} 

Ensuite, le code ressemblerait à ce qui suit:

ZipInputStream zis = new ZipInputStream(new FileInputStream(ZIPPATH)); 
for (ZipEntry ze = zis.getNextEntry(); ze!=null; ze = zis.getNextEntry()) { 
    Process decoder = new ProcessBuilder(EXTERNALPROCESSOR).start(); 
    CopyStream cs1 = new CopyStream(is,false,decoder.getOutputStream(),true,true); 
    CopyStream cs2 = new CopyStream(decoder.getErrorStream(),true,System.err,false,true); 
    BufferedReader br = new BufferedReader(new InputStreamReader(decoder.getInputStream(),"us-ascii")); 
    ArrayList<String> lines = new ArrayList<String>(); 
    for (String line = br.readLine(); line!=null; line = br.readLine()) { 
     lines.add(line); 
    } 
    if (decoder.exitValue()!=0) throw new IOException("Decoder exits with "+decoder.exitValue()); 
    try { 
     cs1.join(100); 
    } catch (InterruptedException ex) { 
     throw new IOException(ex); 
    } 
    if (cs1.isAlive()) throw new IOException("cs1 not terminated"); 
    if (cs1.ex!=null) throw cs1.ex; 
    try { 
     cs2.join(100); 
    } catch (InterruptedException ex) { 
     throw new IOException(ex); 
    } 
    if (cs2.isAlive()) throw new IOException("cs2 not terminated"); 
    if (cs2.ex!=null) throw cs2.ex; 
    for (String line: lines) { 
     processline(line); 
    } 
} 

Cependant, je trouve cela un peu fragile. N'est-ce pas un modèle pour lequel une mise en œuvre plus robuste est autour?