如何检查生成的zip文件是否损坏?

问题描述 投票:0回答:9

我们有一段代码可以在我们的系统上生成 zip 文件。一切正常,但有时此 zip 文件在由 FilZip 或 WinZip 打开时被认为已损坏。

所以这是我的问题:我们如何以编程方式检查生成的 zip 文件是否已损坏?

这是我们用来生成 zip 文件的代码:

try {
    ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(tmpFile));
    byte[] buffer = new byte[16384];
    int contador = -1;
    for (DigitalFile digitalFile : document.getDigitalFiles().getContent()) {
       ZipEntry entry = new ZipEntry(digitalFile.getName());
       FileInputStream fis = new FileInputStream(digitalFile.getFile());
       try {
          zos.putNextEntry(entry);
          while ((counter = fis.read(buffer)) != -1) {
             zos.write(buffer, 0, counter);
          }
          fis.close();
          zos.closeEntry();
       } catch (IOException ex) {
          throw new OurException("It was not possible to read this file " + arquivo.getId());
       }
    }
    try {
      zos.close();
    } catch (IOException ex) {
      throw new OurException("We couldn't close this stream", ex);
    }

我们这里有什么做错的地方吗?

编辑: 其实上面的代码是完全没问题的。我的问题是我为我的用户重定向了错误的流。因此,他们不是打开 zip 文件,而是打开完全不同的文件。抱歉 :(

但主要问题仍然是:如何以编程方式验证给定的 zip 文件是否未损坏?

java zip
9个回答
35
投票

您可以使用

ZipFile
类来检查您的文件:

 static boolean isValid(final File file) {
    ZipFile zipfile = null;
    try {
        zipfile = new ZipFile(file);
        return true;
    } catch (IOException e) {
        return false;
    } finally {
        try {
            if (zipfile != null) {
                zipfile.close();
                zipfile = null;
            }
        } catch (IOException e) {
        }
    }
}

11
投票

我知道这个发布已经有一段时间了,我已经使用了你们所有人提供的代码并提出了这个。这对于实际问题非常有效。检查 zip 文件是否损坏

private boolean isValid(File file) {
    ZipFile zipfile = null;
    ZipInputStream zis = null;
    try {
        zipfile = new ZipFile(file);
        zis = new ZipInputStream(new FileInputStream(file));
        ZipEntry ze = zis.getNextEntry();
        if(ze == null) {
            return false;
        }
        while(ze != null) {
            // if it throws an exception fetching any of the following then we know the file is corrupted.
            zipfile.getInputStream(ze);
            ze.getCrc();
            ze.getCompressedSize();
            ze.getName();
            ze = zis.getNextEntry();
        } 
        return true;
    } catch (ZipException e) {
        return false;
    } catch (IOException e) {
        return false;
    } finally {
        try {
            if (zipfile != null) {
                zipfile.close();
                zipfile = null;
            }
        } catch (IOException e) {
            return false;
        } try {
            if (zis != null) {
                zis.close();
                zis = null;
            }
        } catch (IOException e) {
            return false;
        }

    }
}

3
投票

我想您会在 zip 文件生成过程中看到相应的异常堆栈跟踪。因此,您可能不想增强异常处理。


2
投票

在我的实现中它看起来像这样。也许对你有帮助:

//[...]

try {
    FileInputStream fis = new FileInputStream(file);
    BufferedInputStream bis = new BufferedInputStream(fis);

    zos.putNextEntry(new ZipEntry(file.getName()));

    try {
        final byte[] buf = new byte[BUFFER_SIZE];
        while (true) {
            final int len = bis.read(buf);
            if (len == -1) {
                break;
            }
            zos.write(buf, 0, len);
        }
        zos.flush();
        zos.closeEntry();
    } finally {
        try {
            bis.close();
        } catch (IOException e) {
            LOG.debug("Buffered Stream closing failed");
        } finally {
            fis.close();
        }
    }
} catch (IOException e) {
    throw new Exception(e);
}

//[...]
zos.close

1
投票

也许交换以下两行?;

fis.close();
zos.closeEntry();

我可以想象 closeEntry() 仍然会从流中读取一些数据。


1
投票

你的代码基本上没问题,尝试找出哪个文件导致了损坏的zip文件。检查 digitalFile.getFile() 是否始终向 FileInputStream 返回有效且可访问的参数。只需在代码中添加一些日志记录,您就会发现问题所在。


1
投票
new ZipFile(file) 

再次压缩文件,因此重复工作,这不是您想要的。尽管只检查一个文件,但问题是压缩 n 个文件。

看看这个:http://www.kodejava.org/examples/336.html

为您的 zip 创建校验和:

CheckedOutputStream checksum = new CheckedOutputStream(fos, new CRC32());
ZipOutputStream zos = new ZipOutputStream(new BufferedOutputStream(checksum));
...

当你完成压缩后显示它

System.out.println("Checksum   : " + checksum.getChecksum().getValue());

您必须使用 java 或其他工具执行相同的读取 zip 操作,检查校验和是否匹配。

请参阅https://stackoverflow.com/a/10689488/848072了解更多信息


0
投票

ZipOutputStream 不关闭底层流。

你需要做的是:

FileOutputStream fos = new FileOutputStream(...);
ZipOutputStream zos = new ZipOutputStream(fos);

然后在你的结束语中:

zos.close();
fos.flush(); // Can't remember whether this is necessary off the top of my head!
fos.close();

0
投票

我通过使用 try-with-resources 简化了

Nikhil Das Nomula
的代码:

    public static boolean isValidZipFile(File file) {
        try(ZipFile zipfile = new ZipFile(file); 
            ZipInputStream zis = new ZipInputStream(new FileInputStream(file))
        ) {
            ZipEntry ze = zis.getNextEntry();
            if (ze == null) {
                return false;
            }
            while (ze != null) {
                // if it throws an exception fetching any of the following then we know the file is corrupted.
                zipfile.getInputStream(ze);
                ze.getCrc();
                ze.getCompressedSize();
                ze.getName();

                ze = zis.getNextEntry();
            }
            return true;
        } catch (Exception e) {
            return false;
        }
    }

一开始我认为使用

ZipFile
是多余的,但后来我删除了存档文件末尾的一个字节。
ZipEntry
没有显示问题,但是
ZipFile
抛出了错误
java.util.zip.ZipException: zip END header not found

© www.soinside.com 2019 - 2024. All rights reserved.