检测流是否使用Java压缩的最佳方法

找出java.io.InputStream包含压缩数据的最佳方法是什么?

ZIP格式的神奇字节是50 4B 。 您可以测试流(使用标记和重置 – 您可能需要缓冲 )但我不希望这是100%可靠的方法。 没有办法将它与以字母PK开头的US-ASCII编码文本文件区分开来。

最好的方法是在打开流之前提供内容格式的元数据,然后对其进行适当处理。

介绍

由于所有答案都是5年,我觉得有责任写下今天发生的事情。 我严重怀疑应该读取流的神奇字节! 这是一个低级代码,一般应该避免。

简单的回答

miku写道:

如果可以通过ZipInputStream读取Stream,则应该压缩它。

是的,但是在ZipInputStream情况下“可以读取”意味着第一次调用.getNextEntry()返回一个非空值。 没有例外捕获等等。 因此,您可以执行以下操作,而不是魔术字节解析:

 boolean isZipped = new ZipInputStream(yourInputStream).getNextEntry() != null; 

就是这样!

一般解压缩思想

一般来说,与[stream]压缩文件相比,使用文件更方便。 有几个有用的库,加上ZipFile比ZipInputStream有更多的function。 这里讨论zip文件的处理: 压缩/解压缩文件的优秀Java库是什么? 因此,如果您可以使用文件,您最好这样做!

代码示例

我的应用程序中只需要使用流。 这就是我为解压缩而编写的方法:

 import org.apache.commons.io.IOUtils; import java.util.zip.ZipEntry; import java.util.zip.ZipInputStream; public boolean unzip(InputStream inputStream, File outputFolder) throws IOException { ZipInputStream zis = new ZipInputStream(inputStream); ZipEntry entry; boolean isEmpty = true; while ((entry = zis.getNextEntry()) != null) { isEmpty = false; File newFile = new File(outputFolder, entry.getName()); if (newFile.getParentFile().mkdirs() && !entry.isDirectory()) { FileOutputStream fos = new FileOutputStream(newFile); IOUtils.copy(zis, fos); IOUtils.closeQuietly(fos); } } IOUtils.closeQuietly(zis); return !isEmpty; } 

您可以检查流的前四个字节是本地文件头签名 ,该签名启动本地文件头 ,该头文件继续ZIP文件中的每个文件, 如此处的规范所示为50 4B 03 04

一个小测试代码显示这个工作:

 byte[] buffer = new byte[4]; try { ZipOutputStream zos = new ZipOutputStream(new FileOutputStream("so.zip")); ZipEntry ze = new ZipEntry("HelloWorld.txt"); zos.putNextEntry(ze); zos.write("Hello world".getBytes()); zos.close(); FileInputStream is = new FileInputStream("so.zip"); is.read(buffer); is.close(); } catch(IOException e) { e.printStackTrace(); } for (byte b : buffer) { System.out.printf("%H ",b); } 

给我这个输出:

 50 4B 3 4 

不是很优雅,但可靠:

如果可以通过ZipInputStream读取Stream,则应该压缩它。

检查幻数可能不是正确的选择。

Docx文件也具有相似的幻数50 4B 3 4