Передача данных из InputStream в OutputStream в Java - PullRequest
2 голосов
/ 18 апреля 2010

Я хотел бы отправить файл, содержащийся в 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()? Я предполагаю, что выделенный поток необходим, поскольку процесс декодера может блокироваться, когда его вывод не используется.

Ответы [ 2 ]

3 голосов
/ 18 апреля 2010

Да, необходим поток (или вы ждете / блокируете до завершения копирования) для копирования InputStream в OutputStream. Проверьте класс org.apache.commons.net.io.Util на наличие нескольких вспомогательных методов для копирования данных.

0 голосов
/ 19 апреля 2010

Хорошо, я дошел до следующего:

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

Однако я нахожу это немного хрупким. Разве это не шаблон, для которого существует более надежная реализация?

...