我们需要确定传入的InputStream是否是对zip文件或zip数据的引用。我们没有引用流的基础源。我们的目标是将此流的内容复制到指向备用位置的OutputStream。
我尝试使用ZipInputStream读取流并提取ZipEntry。如果流是常规文件,ZipEntry为null - 正如预期的那样 - 但是,在检查ZipEntry时,我从流中丢失了初始的几个字节。因此,当我知道流是常规流时,我已经丢失了流中的初始数据。
关于如何检查InputStream是否是没有数据丢失的存档的任何想法都会有所帮助。
感谢。
答案 0 :(得分:6)
假设你的原始输入流没有被缓冲,我会尝试将原始流包装在BufferedInputStream中,然后将其包装在ZipInputStream中进行检查。您可以在检查后使用BufferedInputStream中的“mark”和“reset”返回到流中的初始位置。
答案 1 :(得分:3)
这就是我做到的。
如果GZIPInputStream检测到不正确的zip格式,则使用mark / reset恢复流(抛出ZipException)。
/**
* Wraps the input stream with GZIPInputStream if needed.
* @param inputStream
* @return
* @throws IOException
*/
private InputStream wrapIfZip(InputStream inputStream) throws IOException {
if (!inputStream.markSupported()) {
inputStream = new BufferedInputStream(inputStream);
}
inputStream.mark(1000);
try {
return new GZIPInputStream(inputStream);
} catch (ZipException e) {
inputStream.reset();
return inputStream;
}
}
答案 2 :(得分:2)
您可以检查ZIP本地标头签名(PK 0x03 0x04)的流的第一个字节,这对于大多数情况来说已经足够了。如果您需要更高的精度,则应该使用最后的~100个字节并检查中央目录定位器字段。
答案 3 :(得分:0)
这听起来有点像黑客,但你可以实现一个代理java.io.InputStream来放在ZipInputStream和你最初传递给ZipInputStream的构造函数的流之间。您的代理将流式传输到缓冲区,直到您知道它是否是ZIP文件。如果没有,那么缓冲区可以节省您的一天。
答案 4 :(得分:0)
您已经描述过java.io.PushbackInputStream - 除了read()
之外,它还有一个unread(byte[])
,允许您将它们推送到流的前面,并重新{{1}他们又来了。
自JDK1.0以来它位于read()
(虽然我承认直到今天我还没有看到它的使用)。