1、问题
linux下面压缩文件默认用utf-8,windows下面是GBK。乱码主要是由于不同的字符集相互转换导致的,理论上各个字符的编码规则是不同的,是不能相互转换的,所以根本解决乱码的方法就是不要转换编码方式,编码方式前后统一。
2、分析
源代码,需要兼容GBK和UTF-8两种编码方式
public Integer synBatchUploadEmployees(MultipartFile file) {
//此处解压默认是UTF-8
ZipArchiveInputStream zipInputStream = new ZipArchiveInputStream(new ByteArrayInputStream(file.getBytes()));
ZipArchiveEntry zipArchiveEntry = null;
while ((zipArchiveEntry = zipArchiveInputStream.getNextZipEntry()) != null) {
System.out.println(zipArchiveEntry.getName());
}
}
3、方案
判断上传的文件编码类型
- 依赖包pom.xml
<dependency>
<groupId>net.lingala.zip4j</groupId>
<artifactId>zip4j</artifactId>
<version>2.2.8</version>
</dependency>
- 代码
public static void getMultipartFileEncoding(MultipartFile multipartFile) throws Exception {
String path = "/Users/spark/Desktop/data";
if (!new File(path).exists()) {
new File(path).mkdirs();
}
String destPath = "/Users/spark/Desktop/data/" + UUID.randomUUID().toString() + multipartFile.getName();
File dest = new File(destPath);
multipartFile.transferTo(dest);
System.out.println(Charset.forName(getEncoding(destPath)));
dest.delete();
}
@SuppressWarnings("unchecked")
private static String getEncoding(String path) throws Exception {
String encoding = "GBK";
ZipFile zipFile = new ZipFile(path);
zipFile.setCharset(Charset.forName(encoding));
List<FileHeader> list = zipFile.getFileHeaders();
for (int i = 0; i < list.size(); i++) {
FileHeader fileHeader = list.get(i);
String fileName = fileHeader.getFileName();
if (isMessyCode(fileName)) {
encoding = "UTF-8";
break;
}
}
return encoding;
}
private static boolean isMessyCode(String str) {
for (int i = 0; i < str.length(); i++) {
char c = str.charAt(i);
// 当从Unicode编码向某个字符集转换时,如果在该字符集中没有对应的编码,则得到0x3f(即问号字符?)
// 从其他字符集向Unicode编码转换时,如果这个二进制数在该字符集中没有标识任何的字符,则得到的结果是0xfffd
if ((int) c == 0xfffd) {
// 存在乱码
return true;
}
}
return false;
}
4、方案弊端
- 需要临时保存压缩文件,暂用磁盘空间。
- 需要遍历文件,若压缩文件中文件过多,而中文命名乱码过少,增加请求的耗时。