我们有一段代码可以在我们的系统上生成 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 文件是否未损坏?
您可以使用
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) {
}
}
}
我知道这个发布已经有一段时间了,我已经使用了你们所有人提供的代码并提出了这个。这对于实际问题非常有效。检查 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;
}
}
}
我想您会在 zip 文件生成过程中看到相应的异常堆栈跟踪。因此,您可能不想增强异常处理。
在我的实现中它看起来像这样。也许对你有帮助:
//[...]
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
也许交换以下两行?;
fis.close();
zos.closeEntry();
我可以想象 closeEntry() 仍然会从流中读取一些数据。
你的代码基本上没问题,尝试找出哪个文件导致了损坏的zip文件。检查 digitalFile.getFile() 是否始终向 FileInputStream 返回有效且可访问的参数。只需在代码中添加一些日志记录,您就会发现问题所在。
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 操作,检查校验和是否匹配。
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();
我通过使用 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
。