检测流是否使用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