如何检测文件类型从它的内容在zip存档?



我有一个包含几个gzip文件的zip归档文件。但是gzip文件的扩展名也是.zip。我使用ZipInputStream浏览zip存档。我如何通过读取其内容而不是扩展名来检测内部文件的类型?我也不需要改变(或重置)ZipInputStream的位置。

所以我需要;

  • 使用inputStream (ZipInputStream在我的情况下)读取zip文件,因为zip中的zip是可能的。
  • 查找文件类型
  • 当从其内容中查找文件类型时,inputStream的位置不应该改变。因为我会继续读取下一个文件。

例子:

root/1.zip/2.zip/3.zip(实际上3是gzip)/4.txt

示例Java代码:

public static void main(String[] args) {
//root/1.zip/2.zip/3.zip(actually 3 is gzip)/4.txt
String file = "root/1.zip";
File rootZip = new File(file);
try (FileInputStream fis = new FileInputStream(rootZip)) {
lookupInZip(fis)
.stream()
.forEach(System.out::println);
} catch (IOException e) {
System.out.println("Failed to get files");
}
}
public static List<String> lookupInZip(InputStream inputStream) throws IOException {
Tika tika = new Tika();
List<String> paths = new ArrayList<>();
ZipInputStream zipInputStream = new ZipInputStream(inputStream);
ZipEntry entry = zipInputStream.getNextEntry();
while (entry != null) {
String entryName = entry.getName();
if (!entry.isDirectory()) {
//Option 1
//String fileType = tika.detect(entryName);
//Option 2
String fileType = tika.detect(zipInputStream);
if ("application/zip".equals(fileType)) {
List<String> innerPaths = lookupInZip(zipInputStream);
paths.addAll(innerPaths);
} else {
paths.add(entryName);
}
}
entry = zipInputStream.getNextEntry();
}
return paths;
}

如果我使用选项1,'3.zip'被评估为zip文件,但它是gzip。如果我使用选项2,通过使用其内容,'2.zip'将被正确地计算为zip。但是当对'3.zip'递归调用lookupInZip()时,zipInputStream.getNextEntry()返回null。因为在前面的步骤中,我们使用inputStream内容来检测类型和inputStream位置的变化。

注意:tika.detect()在实现中使用BufferedInputStream来重置inputStream的位置,但它不能解决我的问题。

前两个字节足以判断它可能是zip文件,可能是gzip文件,或者肯定是其他文件。

如果前两个字节是0x50 0x4b,那么它可能是一个zip文件。如果前两个字节是0x1f 0x8b,那么它可能是一个gzip文件。如果两者都不是,则该文件为其他文件。

前两个字节匹配并不能保证它是那种类型,但从你的结构来看,它通常是其中之一,你可以使用扩展名作为进一步证实它被压缩的证据。

至于不改变位置,您需要一种方法在不移动位置的情况下窥视前两个字节,或者一种方法获取它们然后取消它们以返回位置。

最新更新