Java ZIP 压缩与解压时处理中文文件名及目录乱码解决方案

更新时间:2024-04-21 19:14:43   人气:9446
在进行文件的压缩和解压操作过程中,特别是在使用Java标准库中的`java.util.zip.*`包来处理ZIP格式的归档文件时,在包含有非英文字符(如汉字)的文件或目录名称的情况下,可能会出现编码问题导致乱码现象。这是因为Java默认对UTF-8或其他Unicode编码的支持并不完善。

要解决这个问题,我们需要明确两个关键点:读取/创建zip文件时正确指定输入输出流的charset以及妥善处理ZipEntry中涉及到字符串的部分。

首先,在构造 ` ZipOutputStream ` 或者 ` ZipInputStream ` 时,并不能直接设置其内部使用的 charset ,但可以通过包装字节流的方式来间接实现:

java

// 创建一个支持GBK编码的 FileOutputStream 和 BufferedOutputStream
FileOutputStream fos = new FileOutputStream("archive.zip");
BufferedOutputStream bos = new BufferedOutputStream(fos);
Charset setEncodingToGb2312 = Charset.forName("GB2312"); // 根据实际需要选择合适的编码方式

// 使用转换流将原生IO流转为自定义编码的输出流
OutputStream out = new OutputStreamWriter(bos, setEncodingToGb2312).getOutputStream();

// 构造并配置 ZipOutputStream
ZipOutputStream zos = new ZipOutputStream(out);

...

zos.putNextEntry(new ZipEntry(file.getName().getBytes(setEncodingToGb2312.name())));

...

上述代码片段展示了如何以 GBK 编码的方式新建 ZIP 输出流并对含有中文路径名的文件添加到 zip 归档里去的过程。对于解压过程也是类似的逻辑,需确保从 ZipInputStream 中获取出的 entry 名称用相同的编码方式进行还原:

java

ZipInputStream zis = new ZipInputStream(new FileInputStream("archive.zip"));
zis.getNextEntry();
byte[] encodedBytes = zis.getCurrentEntryName().getBytes(Charset.forName("ISO-8859-1")); // 先按PKWare规范拿到原始Byte数组
String decodedFileName = new String(encodedBytes, "GB2312"); // 再按照正确的文本编码解析成字符串


然而更推荐的做法是遵循 PKWARE 的 Unicode 路径扩展规范 (APPENDIX D of APPNOTE.TXT),该规范允许存储 UTF-8 编码的文件名且不需要额外设定:

java

try(ZipOutputStream zout = new ZipOutputStream(Files.newOutputStream(zipPath))) {
for(Path file : filesToAdd) {
Path absoluteFilePath = file.toAbsolutePath();
ZipEntry ze= new ZipEntry(absoluteFilePath.toString());
ze.setComment(String.format("%s created on %tc", absoluteFilePath.getFileName(), System.currentTimeMillis()));

// 设置名字编码方式为 utf-8 并保存进 extra 字段
byte[] fileNameInUtf8 = Files.readAllLines(absoluteFilePath.getParent()).toArray()[0].getBytes(StandardCharsets.UTF_8);
ze.setName(fileNameInUtf8);
ze.setSize(Files.size(absoluteFilePath));

zout.putNextEntry(ze);
Files.copy(absoluteFilePath, zout);
zout.closeEntry();
}
} catch(...) {...}

// 解压时无需特殊处理即可正常显示中文名

通过这种方式构建和解读Zip条目可以避免大部分由于编码不一致造成的中文文件名混乱的问题。同时注意无论是压缩还是解压的过程中,都要尽可能保持两端系统环境、程序设计所采用的字符集的一致性才能有效防止乱码情况的发生。