我目前正在嘗試編寫一個自定義流代理(讓我們以這種方式調用它),它可以更改給定輸入流中的內容並生成修改後的輸出(如有必要)。這個要求是非常必要的,因爲有時我必須修改我的應用程序中的流(例如,在運行時真正地壓縮數據)。下面的類很容易,它使用內部緩衝。僅使用InputStream和OutputStream抽象在Java中進行壓縮(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格式和deflate壓縮是專爲即時工作而設計的。
可能我在某些時候對deflate壓縮算法的細節有誤。我真的錯過了什麼?也許可能有另一種方法來編寫一個「流代理」,以使其行爲與我希望的一樣工作......我如何才能將流中的數據壓縮爲僅受流限制?
在此先感謝。
UPD:以下基本版本的作品相當不錯的用deflater和吹氣:
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 2012-01-17 16:54:21
'ByteArrayOutputStream'!='BufferedOutputStream'。非常非常。 – Viruzzo 2012-01-17 16:55:52