【问题标题】:Pipe data from InputStream to OutputStream in Java在 Java 中将数据从 InputStream 管道传输到 OutputStream
【发布时间】:2010-04-17 20:44:40
【问题描述】:

我想将一个包含在 ZIP 压缩包中的文件解压后发送到外部程序,以便进一步解码并将结果读回 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()) {
    ...
}

我需要在??? 中添加什么内容才能将zis 内容通过管道传输到decoder.getOutputStream()?我想需要一个专用线程,因为解码器进程可能会在其输出未被消耗时阻塞。

【问题讨论】:

  • Zip 解码并不是很昂贵——将解压缩文件卸载到另一个进程的开销可能不仅仅是在本地解压缩文件。 java.util.zip.Inflater 将为您完成所有工作。
  • 我澄清了我的帖子,这似乎有点误导。除了解压缩之外,解码器还应该做其他事情。

标签: java multithreading pipe io


【解决方案1】:

是的,将 InputStream 复制到 OutputStream 需要一个线程(或者您等待/阻塞直到复制完成)。检查org.apache.commons.net.io.Util 类中的几个帮助方法来复制数据。

【讨论】:

  • 好吧,来自 org.apache.commons.net.io.Util 的 copyStream 没有线程化,所以基本上问题仍然存在......
  • @Wangnick:正如我所说,你需要一个线程。 copyStream 方法只是一个辅助方法,你还是要把它放在一个 Thread/Runnable 对象中。
  • 是的,我知道,请参阅原始问题。不幸的是,它并不像你说的那么简单......
【解决方案2】:

好的,我知道了:

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

那么代码将如下所示:

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

但是,我觉得这有点脆弱。这不是一种更强大的实现模式吗?

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-07-27
    • 2014-03-30
    • 2018-12-19
    • 2015-05-10
    • 1970-01-01
    • 2016-08-27
    相关资源
    最近更新 更多