gpt4 book ai didi

java - 仅使用 InputStream 和 OutputStream 抽象在 Java 中即时压缩 (ZIP)。可能的?

转载 作者:搜寻专家 更新时间:2023-11-01 01:46:25 26 4
gpt4 key购买 nike

我目前正在尝试编写一个自定义流代理(让我们这样调用它),它可以更改给定输入流的内容,并在必要时生成经过修改的输出。这个要求确实是必要的,因为有时我必须修改我的应用程序中的流(例如,真正即时压缩数据)。下面的类非常简单,它使用内部缓冲。

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”->“a b c”)之前添加一个空格字符,如下所示:

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 的情况下调用测试方法,它的行为会非常奇怪并且几乎什么都不写(如果省略 header 78 9C)。我怀疑 deflater 类的设计可能无法满足我喜欢使用的方法,但我始终相信 ZIP 格式和 deflate 压缩是为即时工作而设计的。

可能我在某些时候对 deflate 压缩算法的细节有误。我真正想念的是什么?..也许可以有另一种方法来编写一个“流代理”来完全按照我想要的方式工作......我如何在仅限于流的情况下动态压缩数据?

提前致谢。


UPD:以下基本版本与 deflater 和 inflater 配合得很好:

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

最佳答案

我不相信 DeflaterOutputStream.flush() 会做任何有意义的事情。 deflater 将累积数据,直到它有东西可以写到底层流中。强制输出剩余数据位的唯一方法是调用 DeflaterOutputStream.finish()。但是,这对您当前的实现不起作用,因为在完全完成编写之前您不能调用 finish。

实际上很难在同一个线程中编写和读取压缩流。在RMIIO项目我实际上是这样做的,但是您需要一个任意大小的中间输出缓冲区(并且您基本上需要将数据插入直到另一端压缩出来,然后您可以读取它)。您也许能够使用该项目中的一些实用程序类来完成您想要做的事情。

关于java - 仅使用 InputStream 和 OutputStream 抽象在 Java 中即时压缩 (ZIP)。可能的?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8898434/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com