使用zip4j解压zip时文件名乱码解决最好的方案
zip4j解压zip时,出现中文乱码,看了下,zip4j解压时支持设置文件编码,我们只需要识别文件是不是utf-8编码,如果不是utf-8就使用gbk解压,但是这个判断没有100%准确的方式,我试过通过字节流的bom标记去判断,但是文件不一定有bom字节,所以不适用。
网上最多的判断方式是使用第三方jar工具cpdetecpor或juniversalchardet,但是这两种方式我都尝试过,juniversalchardet无法判断出文件编码,而cpdetecpor可以得到一个判断结果,但是也不准确,我经过一两天的探索查找,找到了一个比较靠谱的方式:
/**
* 解压
*/
@SneakyThrows
public static void unzipFile(String zipFilePath, String destFilePath, String password) {
ZipFile zipFile = null;
try {
zipFile = new ZipFile(zipFilePath);
zipFile.setCharset(StandardCharsets.UTF_8);
List<FileHeader> headers = zipFile.getFileHeaders();
//判断文件名是否有乱码,有乱码,将编码格式设置成GBK
if (isRandomCode(headers)) {
log.info("使用UTF-8解压文件【{}】时乱码,尝试使用GBK重新解压",zipFilePath);
zipFile.close();
zipFile = new ZipFile(zipFilePath);
zipFile.setCharset(Charset.forName("GBK"));
}
if (!zipFile.isValidZipFile()) {
throw new VerifyException("压缩文件不合法,可能被损坏.");
}
if (zipFile.isEncrypted() && StringTool.isNotBlank(password)) {//加密zip,且输入的密码不为空,直接进行解密。
zipFile.setPassword(password.toCharArray());
}
FileTool.createDir(destFilePath);
zipFile.extractAll(destFilePath);
}finally {
IOUtils.closeQuietly(zipFile,null);
}
}
private static boolean isRandomCode(List<FileHeader> fileHeaders) {
for (FileHeader fileHeader : fileHeaders) {
boolean canEnCode = Charset.forName("GBK").newEncoder().canEncode(fileHeader.getFileName());
if (!canEnCode) {//canEnCode为true,表示不是乱码。false.表示乱码。是乱码则需要重新设置编码格式
return true;
}
}
return false;
}
我们先使用utf-8读取zip里面的文件名,然后判断文件名是否能使用gbk进行编码,如果不能,我们就用utf-8解压,如果gbk可以编码,就使用gbk进行解压