私は現在、指定された入力ストリームからコンテンツを変更し、必要に応じて出力を変更できるカスタムストリームプロキシを作成しようとしています(そのように呼びます)。アプリケーションでストリームを変更する必要がある場合があります(例えば、実際にデータを圧縮する場合は、をオンフックしてください))この要件は本当に必要です。次のクラスはかなり簡単で、内部バッファリングを使用します。JavaでInputStreamとOutputStreamの抽象化のみを使用して圧縮を圧縮(ZIP)します。可能?
private static class ProxyInputStream extends InputStream {
private final InputStream iStream;
private final byte[] iBuffer = new byte[512];
private int iBufferedBytes;
private final ByteArrayOutputStream oBufferStream;
private final OutputStream oStream;
private byte[] oBuffer = emptyPrimitiveByteArray;
private int oBufferIndex;
ProxyInputStream(InputStream iStream, IFunction<OutputStream, ByteArrayOutputStream> oStreamFactory) {
this.iStream = iStream;
oBufferStream = new ByteArrayOutputStream(512);
oStream = oStreamFactory.evaluate(oBufferStream);
}
@Override
public int read() throws IOException {
if (oBufferIndex == oBuffer.length) {
iBufferedBytes = iStream.read(iBuffer);
if (iBufferedBytes == -1) {
return -1;
}
oBufferIndex = 0;
oStream.write(iBuffer, 0, iBufferedBytes);
oStream.flush();
oBuffer = oBufferStream.toByteArray();
oBufferStream.reset();
}
return oBuffer[oBufferIndex++];
}
}
のは、我々は、単にすべての書かれたバイトの前に空白文字を追加するサンプルテスト出力ストリーム持っていると仮定しましょう - このような(「ABC」>「ABC」):
private static class SpacingOutputStream extends OutputStream {
private final OutputStream outputStream;
SpacingOutputStream(OutputStream outputStream) {
this.outputStream = outputStream;
}
@Override
public void write(int b) throws IOException {
outputStream.write(' ');
outputStream.write(b);
}
}
して、次のようにテスト方法:
private static void test(final boolean useDeflater) throws IOException {
final FileInputStream input = new FileInputStream(SOURCE);
final IFunction<OutputStream, ByteArrayOutputStream> outputFactory = new IFunction<OutputStream, ByteArrayOutputStream>() {
@Override
public OutputStream evaluate(ByteArrayOutputStream outputStream) {
return useDeflater ? new DeflaterOutputStream(outputStream) : new SpacingOutputStream(outputStream);
}
};
final InputStream proxyInput = new ProxyInputStream(input, outputFactory);
final OutputStream output = new FileOutputStream(SOURCE + ".~" + useDeflater);
int c;
while ((c = proxyInput.read()) != -1) {
output.write(c);
}
output.close();
proxyInput.close();
}
このテスト方法は、単にファイルの内容を読み取り、それを別のストリームに書き込むだけで、おそらく何らかの修正が可能です。テストメソッドがuseDeflater=false
で実行されている場合、期待どおりのアプローチは正常に動作します。しかし、useDeflater
をオンにしてテストメソッドを呼び出すと、実際には奇妙に動作し、ほとんど何も書き込まれません(ヘッダ78 9C
を省略した場合)。私はdeflaterクラスが私が使いたいと思うアプローチに合うように設計されていないかもしれないと思うが、私はいつもZIP形式と圧縮の圧縮はオンザフライで動作するように設計されていると信じている。
おそらく、私は、デフレート圧縮アルゴリズムの仕様について間違っています。私が実際に見逃していることは?おそらく、ストリーム・プロキシーを書いて、動作させたいのと同じように動作する別の方法があるかもしれません。ストリームでのみ制限されているデータを圧縮するにはどうすればいいですか?
ありがとうございます。
UPD:次の基本的なバージョンデフレータとインフレータとかなりいい作品:GZipOutputStreamを使用していないのはなぜ
public final class ProxyInputStream<OS extends OutputStream> extends InputStream {
private static final int INPUT_BUFFER_SIZE = 512;
private static final int OUTPUT_BUFFER_SIZE = 512;
private final InputStream iStream;
private final byte[] iBuffer = new byte[INPUT_BUFFER_SIZE];
private final ByteArrayOutputStream oBufferStream;
private final OS oStream;
private final IProxyInputStreamListener<OS> listener;
private byte[] oBuffer = emptyPrimitiveByteArray;
private int oBufferIndex;
private boolean endOfStream;
private ProxyInputStream(InputStream iStream, IFunction<OS, ByteArrayOutputStream> oStreamFactory, IProxyInputStreamListener<OS> listener) {
this.iStream = iStream;
oBufferStream = new ByteArrayOutputStream(OUTPUT_BUFFER_SIZE);
oStream = oStreamFactory.evaluate(oBufferStream);
this.listener = listener;
}
public static <OS extends OutputStream> ProxyInputStream<OS> proxyInputStream(InputStream iStream, IFunction<OS, ByteArrayOutputStream> oStreamFactory, IProxyInputStreamListener<OS> listener) {
return new ProxyInputStream<OS>(iStream, oStreamFactory, listener);
}
@Override
public int read() throws IOException {
if (oBufferIndex == oBuffer.length) {
if (endOfStream) {
return -1;
} else {
oBufferIndex = 0;
do {
final int iBufferedBytes = iStream.read(iBuffer);
if (iBufferedBytes == -1) {
if (listener != null) {
listener.afterEndOfStream(oStream);
}
endOfStream = true;
break;
}
oStream.write(iBuffer, 0, iBufferedBytes);
oStream.flush();
} while (oBufferStream.size() == 0);
oBuffer = oBufferStream.toByteArray();
oBufferStream.reset();
}
}
return !endOfStream || oBuffer.length != 0 ? (int) oBuffer[oBufferIndex++] & 0xFF : -1;
}
}
を動けなくなり、私は少し迷ってしまいました、注意してください。しかし、圧縮したくないときは元の 'outputStream'を使い、圧縮したいときは' new GZipOutputStream(outputStream) 'を使います。それで全部です。とにかく、出力ストリームをフラッシュしていることを確認してください。 – helios
'ByteArrayOutputStream'!=' BufferedOutputStream'です。まさにその通り。 – Viruzzo