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

时间:2009-11-27 14:10:45

标签: java zip inputstream

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

7 个答案:

答案 0 :(得分:37)

<强>简介

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

简单回答

miku写道:

  

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

是的,但如果是ZipInputStream&#34;可以阅读&#34;表示第一次调用.getNextEntry()会返回非空值。没有例外捕获等等。因此,您可以执行以下操作而不是魔术字节解析:

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

那就是它!

一般解压缩想法

一般来说,在使用流时,使用[un]压缩文件时,使用文件会更方便。有几个有用的库,加上ZipFile比ZipInputStream有更多的功能。这里讨论zip文件的处理:What is a good Java library to zip/unzip files?因此,如果你可以处理文件,你最好这样做!

代码示例

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

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

答案 1 :(得分:22)

ZIP格式的magic bytes50 4B。您可以测试流(使用markreset - 您可能需要buffer)但我不希望这是100%可靠的方法。没有办法将它与以字母PK开头的US-ASCII编码文本文件区分开来。

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

答案 2 :(得分:6)

您可以检查流的前四个字节是本地文件头签名,它启动本地文件头,继续执行ZIP文件中的每个文件,{ {3}}为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 

答案 3 :(得分:5)

不是很优雅,但可靠:

如果可以通过ZipInputStream读取流,则应将其压缩。

答案 4 :(得分:0)

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

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

答案 5 :(得分:0)

由于.zip和.xlsx都具有相同的魔术数,因此我找不到有效的zip文件(如果已重命名)。

因此,我已经使用Apache Tika查找确切的文档类型。

即使将文件类型重命名为zip,它也会找到确切的类型。

参考:https://www.baeldung.com/apache-tika

答案 6 :(得分:0)

我结合了@McDowell 和 @Innokenty 到一个小的 lib 函数,您可以将其粘贴到您的项目中:

std::string

你可以像这样使用这个库:

public static boolean isZipStream(InputStream inputStream) {
    if (inputStream == null || !inputStream.markSupported()) {
        throw new IllegalArgumentException("InputStream must support mark-reset. Use BufferedInputstream()");
    }
    boolean isZipped = false;
    try {
        inputStream.mark(2048);
        isZipped = new ZipInputStream(inputStream).getNextEntry() != null;
        inputStream.reset();
    } catch (IOException ex) {
        // cannot be opend as zip.
    }
    return isZipped;
}