这是我参与8月更文挑战的第30天,活动详情查看:8月更文挑战
前言
常见的zip包工具类很多,由于代码中的场景对效率要求也不是很高, 其他几种工具这里不做讨论, 由于项目之前用的是zip4j, 这里讨论的zip解压中文字符问题,是对于zip4j的解决方案.
<dependency>
<groupId>net.lingala.zip4j</groupId>
<artifactId>zip4j</artifactId>
<version>2.6.4</version>
</dependency>
ZIP解压现状
ZIP格式在不同平台上使用不同软件压缩,大致结果为两类:
- Windows下使用WinRAR、好压等工具压缩的文件 特点:文件名为GBK编码
- 使用Linux、MacOS等系统压缩的zip文件 特点:文件名为UTF-8编码
GBK和UTF-8之间的区别参考文章
字符编码那点事:快速理解ASCII、Unicode、GBK和UTF-8
问题描述
代码之前在linux服务做的压缩, 然后上传到minio服务器上, 其他服务通过minio下载到本地解压, 文件包中文英文都没有问题. 新增场景本地可以传一些压缩包上传, 结果导致, 解压出来之后显示乱码, 代码异常, 本地写测试类模拟结果一样也是乱码.
问题代码
测试代码
结果
这种字符乱码问题的原因也很简单就是字符集的问题. 网上解决方案很多, 设置字符集为GBK, 使用ant-jar包解压等等. 没有统一的标准和方案,那么我们可以从API入手, 看看源码有没有预留字符集相关的设置, 找到问题的根本原因, 问题自然迎刃而解。
Zip4J源码分析
默认是UTF-8的形式
完整工具类
import cn.hutool.core.util.CharsetUtil;
import net.lingala.zip4j.ZipFile;
import net.lingala.zip4j.exception.ZipException;
import net.lingala.zip4j.model.FileHeader;
import org.apache.commons.collections.CollectionUtils;
import java.io.File;
import java.nio.charset.Charset;
import java.util.*;
public class MyZipUtils {
/**
* 解压zip包返回所有文件
*
* @param filePath 路径
* @param unZipList 已解压列表
* @return List<File>
* @throws ZipException
*/
public static List<File> scanAndUnzipFile(String filePath, Set<String> unZipList) throws ZipException {
File file = new File(filePath);
List<File> fileList = Arrays.asList(file.listFiles());
List<File> fileListNew = new ArrayList<>();
if (CollectionUtils.isNotEmpty(fileList)) {
for (File file1 : fileList) {
if (file1.getName().indexOf(".zip") != -1) {
if (unZipList.contains(file1.getName())) {
continue;
}
unZipList.add(file1.getName());
ZipFile zipFile1 = new ZipFile(file1);
extractAll(filePath, zipFile1);
return scanAndUnzipFile(filePath, unZipList);
}
fileListNew.add(file1);
}
return fileListNew;
}
return null;
}
public static String extractAll(String filePath, ZipFile zip) {
zip.setCharset(Charset.forName("utf-8"));
System.out.println("begin unpack zip file....");
try {
zip.getFileHeaders().forEach(v->{
String extractedFile = getFileName(v);
try {
zip.extractFile(v, filePath ,extractedFile);
} catch (ZipException e) {
System.out.println("解压失败 :"+ extractedFile);
e.printStackTrace();
return;
}
System.out.println("解压成功 :"+extractedFile);
});
} catch (ZipException e) {
e.printStackTrace();
}
System.out.println("unpack zip file success");
return "success";
}
public static String getFileName(FileHeader fileHeader) {
try {
// 目前压缩包主要是两种来源WINdows和Linux
if (fileHeader.isFileNameUTF8Encoded()) {
return new String(fileHeader.getFileName().getBytes("Cp437"), CharsetUtil.CHARSET_UTF_8.name());
} else {
return new String(fileHeader.getFileName().getBytes("Cp437"), CharsetUtil.CHARSET_GBK.name());
}
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return fileHeader.getFileName();
}