关键在于
zipEntry.isDirectory()
用于判断压缩包内的条目是不是文件夹
/**
* 解压 zip
*
* @param zipFile
* @param descDir
*/
public static void unpack(File zipFile, File descDir) {
try (ZipInputStream inputStream = new ZipInputStream(new FileInputStream(zipFile), Charset.forName("GBK"))) {
if (!descDir.exists()) {
descDir.mkdirs();
}
ZipEntry zipEntry = null;
File outfile = null;
while ((zipEntry = inputStream.getNextEntry()) != null) {
outfile = checkFileDir(descDir, zipEntry.getName());
if (zipEntry.isDirectory()) {
outfile.mkdirs();
} else {
OutputStream os = null;
try {
os = new BufferedOutputStream(new FileOutputStream(new File(descDir, zipEntry.getName())));
IOUtils.copy(inputStream, os);
} finally {
IOUtils.closeQuietly(os);
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* zip 条目覆盖漏洞校验
* 防止压缩包内文件名称包含路径 例:../a.jpg
*
* @param destDir
* @param fileName
* @return
*/
public static File checkFileDir(File destDir, String fileName) {
File destFile = new File(destDir, fileName);
String destDirPath = "";
String destFilePath = "";
try {
destDirPath = destDir.getCanonicalPath();
destFilePath = destFile.getCanonicalPath();
} catch (IOException e) {
throw new RuntimeException(e.getMessage());
}
if (!destFilePath.startsWith(destDirPath + File.separator)) {
throw new RuntimeException("文件不在许可目录内!");
}
// 防止压缩包一级目录只有文件夹时,解压报错找不到文件
File parentDir = destFile.getParentFile();
if(!parentDir.exists()){
parentDir.mkdirs();
}
return destFile;
}
解压过程提示报错:java.lang.IllegalArgumentException: MALFORMED
java.lang.IllegalArgumentException: MALFORMED
at java.util.zip.ZipCoder.toString(ZipCoder.java:58)
at java.util.zip.ZipInputStream.readLOC(ZipInputStream.java:300)
at java.util.zip.ZipInputStream.getNextEntry(ZipInputStream.java:122)
原因
windows环境下,默认字符集为GBK,ZipFile默认使用UTF-8字符集,当文件名存在中文时,处理时就会报错
解决方法
创建 ZipInputStream 时,设置字符集为GBK
ZipInputStream inputStream = new ZipInputStream(new FileInputStream(zipFile), Charset.forName("GBK")