【发布时间】:2014-11-04 19:51:54
【问题描述】:
我有一个将目录内容压缩到 zip 文件中的类。我正在使用的代码如下。我遇到的问题是我生成的 zip 文件无法被我正在加载的应用程序读取。但是,如果我解压缩正在生成的 zip 文件并使用 WinZip 将其重新压缩备份,则可以使用该文件。我无法控制加载 zip 的目标应用程序,所以我所能做的就是让我的文件看起来像 WinZip 生成的版本。我使用 WinZip 详细诊断功能打开了每个 zip 文件,我可以看到生成的文件有很多差异,但我不明白哪些文件可能导致问题。有关示例,请参见问题的底部。
package com.mycompany.utils;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
import org.apache.log4j.Logger;
public class FileZipper {
private static final Logger LOGGER = Logger.getLogger(FileZipper.class);
private String destinationZipFile;
private String sourceDirectory;
List<String> fileList;
private File zipFile;
public File getZipFile() {
return zipFile;
}
/**
* Zips a source directory into the destination zip file
*
* @param source
* @param destination
*/
FileZipper(String source, String destination) {
LOGGER.info("Zipping source directory: "+source);
LOGGER.info("To destination zip file: "+destination);
this.destinationZipFile = destination;
this.sourceDirectory = source;
fileList = new ArrayList<String>();
generateFileList(new File(sourceDirectory));
compressDirectoryContentsToZip(sourceDirectory, destinationZipFile);
}
/**
* Traverse a directory and get all files, and add the file into fileList
*
* @param node
* file or directory
*/
public void generateFileList(File node) {
// add file only
if (node.isFile()) {
fileList.add(generateZipEntry(node.getAbsoluteFile().toString()));
}
if (node.isDirectory()) {
if(node.toString() != sourceDirectory) {
fileList.add(generateZipEntry(node.getAbsoluteFile().toString()));
}
String[] subNodes = node.list();
for (String filename : subNodes) {
generateFileList(new File(node, filename));
}
}
}
/**
* Compress a directory to a zip file
* @param sourceDirectory
* @param destinationZipFile
*/
public void compressDirectoryContentsToZip(String sourceDirectory,
String destinationZipFile) {
this.zipFile = new File(destinationZipFile);
byte[] buffer = new byte[4096];
try {
FileOutputStream fos = new FileOutputStream(destinationZipFile);
BufferedOutputStream bos = new BufferedOutputStream(fos);
ZipOutputStream zos = new ZipOutputStream(bos);
zos.setMethod(ZipOutputStream.DEFLATED);
LOGGER.info("Zipping to : " + destinationZipFile);
for (String entry : this.fileList) {
long fileSizeInBytes = new File(sourceDirectory +
File.separator + entry).length();
if(new File(sourceDirectory + File.separator + entry).isFile()) {
LOGGER.info("File Added : " + entry + " ("+String.valueOf(fileSizeInBytes)+" bytes)");
ZipEntry ze = new ZipEntry(entry);
zos.putNextEntry(ze);
FileInputStream in = new FileInputStream(sourceDirectory
+ File.separator + entry);
int len;
while ((len = in.read(buffer)) > 0) {
zos.write(buffer, 0, len);
}
in.close();
zos.closeEntry();
} else if(new File(sourceDirectory + File.separator + entry).isDirectory()) {
LOGGER.info("Directory Added : " + entry);
ZipEntry ze = new ZipEntry(entry+File.separator);
zos.putNextEntry(ze);
zos.closeEntry();
} else {
LOGGER.warn("Not a file or directory: "+entry);
}
}
zos.closeEntry();
zos.close();
LOGGER.info("Zipping completed successfully");
} catch (IOException ex) {
LOGGER.error(ex);
System.exit(1);
}
LOGGER.info("Generated zip file: "+ destinationZipFile);
}
/**
* Format the filename for archiving by removing the path
* of the source directory
*
* @param file
* @return
*/
private String generateZipEntry(String file) {
LOGGER.debug("Stripping '"+file+"' to '"
+file.substring(sourceDirectory.length() + 1, file.length())+"'");
return file.substring(sourceDirectory.length() + 1, file.length());
}
}
所以我在 WinZip 中生成的 zip 文件诊断中看到的输出如下:
非工作文件
Archive: C:\Users\conor\Desktop\dp-export-2\dp-export-2.zip 3573 bytes 2014-11-04 20:03:22
Current Location part 1 offset 3551
End central directory record PK0506 (4+18)
==========================================
location of end-of-central-dir record: 3551 (0x00000ddf) bytes
part number of this part (0000): 1
part number of start of central dir (0000): 1
number of entries in central dir in this part: 1
total number of entries in central dir: 1
size of central dir: 56 (0x00000038) bytes
relative offset of central dir: 3495 (0x00000da7) bytes
zipfile comment length: 0
Current Location part 1 offset 3495
Central directory entry PK0102 (4+42): #1
======================================
part number in which file begins (0000): 1
relative offset of local header: 0 (0x00000000) bytes
version made by operating system (00): MS-DOS, OS/2, NT FAT
version made by zip software (20): 2.0
operat. system version needed to extract (00): MS-DOS, OS/2, NT FAT
unzip software version needed to extract (20): 2.0
general purpose bit flag (0x0808) (bit 15..0): 0000.1000 0000.1000
file security status (bit 0): not encrypted
extended local header (bit 3): yes
UTF-8 names (bit 11): yes
compression method (08): deflated
compression sub-type (deflation): normal
file last modified on (0x00004564 0x0000a06a): 2014-11-04 20:03:20
32-bit CRC value: 0x07d797c8
compressed size: 3439 bytes
uncompressed size: 24021 bytes
length of filename: 10 characters
length of extra field: 0 bytes
length of file comment: 0 characters
internal file attributes: 0x0000
apparent file type: binary
external file attributes: 0x00000000
non-MSDOS external file attributes: 0x000000
MS-DOS file attributes (0x00): none
filename: export.xml
Current Location part 1 offset 0
Local directory entry PK0304 (4+26): #1
------------------------------------
operat. system version needed to extract (00): MS-DOS, OS/2, NT FAT
unzip software version needed to extract (20): 2.0
general purpose bit flag (0x0808) (bit 15..0): 0000.1000 0000.1000
file security status (bit 0): not encrypted
extended local header (bit 3): yes
UTF-8 names (bit 11): yes
compression method (08): deflated
compression sub-type (deflation): normal
file last modified on (0x00004564 0x0000a06a): 2014-11-04 20:03:20
32-bit CRC value: 0x00000000
compressed size: 0 bytes
uncompressed size: 0 bytes
note: "real" crc and sizes are in the extended local header
length of filename: 10 characters
length of extra field: 0 bytes
filename: export.xml
Testing export.xml OK
Current Location part 1 offset 3479
Extended local dir entry PK0708 (4+12): #1
---------------------------------------
32-bit CRC value: 0x07d797c8
compressed size: 3439 bytes
uncompressed size: 24021 bytes
No errors detected in compressed data of C:\Users\conor\Desktop\dp-export-2\dp-export-2.zip.
从非工作文件的解压缩中重新压缩的工作文件
Archive: C:\Users\conor\Desktop\dp-export-2\dp-export-2b.zip 3564 bytes 2014-11-04 20:04:46
Current Location part 1 offset 3542
End central directory record PK0506 (4+18)
==========================================
location of end-of-central-dir record: 3542 (0x00000dd6) bytes
part number of this part (0000): 1
part number of start of central dir (0000): 1
number of entries in central dir in this part: 1
total number of entries in central dir: 1
size of central dir: 92 (0x0000005c) bytes
relative offset of central dir: 3450 (0x00000d7a) bytes
zipfile comment length: 0
Current Location part 1 offset 3450
Central directory entry PK0102 (4+42): #1
======================================
part number in which file begins (0000): 1
relative offset of local header: 0 (0x00000000) bytes
version made by operating system (00): MS-DOS, OS/2, NT FAT
version made by zip software (20): 2.0
operat. system version needed to extract (00): MS-DOS, OS/2, NT FAT
unzip software version needed to extract (20): 2.0
general purpose bit flag (0x0002) (bit 15..0): 0000.0000 0000.0010
file security status (bit 0): not encrypted
extended local header (bit 3): no
compression method (08): deflated
compression sub-type (deflation): maximum
file last modified on (0x00004564 0x0000a06a): 2014-11-04 20:03:20
32-bit CRC value: 0x07d797c8
compressed size: 3410 bytes
uncompressed size: 24021 bytes
length of filename: 10 characters
length of extra field: 36 bytes
length of file comment: 0 characters
internal file attributes: 0x0001
apparent file type: text
external file attributes: 0x00000020
non-MSDOS external file attributes: 0x000000
MS-DOS file attributes (0x20): arc
filename: export.xml
extra field 0x000a (PKWARE Win32 Filetimes), 4 header and 32 data bytes:
The Extended Timestamps are:
Creation Date: 2014-11-04 20:03:20
Last Modified Date: 2014-11-04 20:03:20
Last Accessed Date: 2014-11-04 20:03:20
Current Location part 1 offset 0
Local directory entry PK0304 (4+26): #1
------------------------------------
operat. system version needed to extract (00): MS-DOS, OS/2, NT FAT
unzip software version needed to extract (20): 2.0
general purpose bit flag (0x0002) (bit 15..0): 0000.0000 0000.0010
file security status (bit 0): not encrypted
extended local header (bit 3): no
compression method (08): deflated
compression sub-type (deflation): maximum
file last modified on (0x00004564 0x0000a06a): 2014-11-04 20:03:20
32-bit CRC value: 0x07d797c8
compressed size: 3410 bytes
uncompressed size: 24021 bytes
length of filename: 10 characters
length of extra field: 0 bytes
filename: export.xml
Testing export.xml OK
No errors detected in compressed data of C:\Users\conor\Desktop\dp-export-2\dp-export-2b.zip.
很明显,我可以在输出中看到差异,但我不明白为什么所有差异都存在,也不知道哪一个是导致失败的原因。在确定为什么我的目标应用程序可能不喜欢 Java 生成的文件的任何帮助将是一个很大的帮助。我有一种暗示,原因是 Java 与 WinZip 计算 CRC 并随后添加到存档中的方式,但我没有遇到此类问题。我的另一个理论是,这是由于内部文件属性。无法解析的示例将“export.xml”显示为二进制数据,但 WinZip 版本将其显示为文本。
【问题讨论】:
-
关于目标应用程序中发生的错误的更多信息?
-
不幸的是,它告诉我的是它无法解析 zip 文件。就其价值而言,它实际上是一个 IBM DataPower 设备。所以是该设备上的固件无法解析文件。
-
一些建议:尝试使用非常简单的文件结构——一个文件是一个好的开始。您可以访问 Unix 吗?尝试使用 unzip 获取 zip 与 winzip zip 中的文件列表。尝试将压缩级别设置为 0。fileanalysis.net/zip 提供有关 zip 文件格式的信息。
-
我尝试了压缩级别 0,也尝试了只使用一个文件并相应地更新了我提供的示例。我通过使用 Apache commons compress library 解决了这个问题。我将在下面发布我的解决方案