开发者

Pipe data from InputStream to OutputStream in Java

开发者 https://www.devze.com 2022-12-27 01:05 出处:网络
I\'d like to send a file contained in a ZIP archive unzipped to an external program for further decoding and to read the result back into Java.

I'd like to send a file contained in a ZIP archive unzipped to an external program for further decoding and to read the result back into 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()) {
    ...
}

What do I need to put into ??? to pipe the zis content to the decoder.getOutputStream()? I guess a dedicated thread is needed, as the decoder process might block when it开发者_如何学运维s output is not consumed.


Yes a thread is needed (or you wait/block until the copy is finished) for copying the InputStream to the OutputStream. Check the org.apache.commons.net.io.Util class for several helper methods to copy the data.


Ok, I got as far as following:

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

Then the code would look as following:

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

However, I find this a bit fragile. Isn't this a pattern for which some more robust implementation is around?

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号