|
@@ -7,52 +7,52 @@ import java.io.InputStream;
|
|
|
import java.nio.charset.Charset;
|
|
|
import java.util.*;
|
|
|
import java.util.zip.ZipEntry;
|
|
|
+import java.util.zip.ZipException;
|
|
|
import java.util.zip.ZipFile;
|
|
|
|
|
|
/**
|
|
|
* 文件工具类
|
|
|
*/
|
|
|
public class FileUtils {
|
|
|
+
|
|
|
/**
|
|
|
- * 解压缩zip文件到指定目录
|
|
|
- *
|
|
|
- * @param zipFilePath
|
|
|
- * @param destDir
|
|
|
- * @throws IOException
|
|
|
+ * 解压ZIP文件,自动尝试UTF-8和GBK编码
|
|
|
*/
|
|
|
public static void unzipAutoCharset(String zipFilePath, String destDir) throws IOException {
|
|
|
try {
|
|
|
- // 先尝试 UTF-8
|
|
|
unzipWithCharset(zipFilePath, destDir, Charset.forName("UTF-8"));
|
|
|
- } catch (IllegalArgumentException | java.nio.charset.MalformedInputException e) {
|
|
|
- // 如果失败,切换到 GBK
|
|
|
+ } catch (ZipException e) { // 捕获ZIP结构或编码问题
|
|
|
unzipWithCharset(zipFilePath, destDir, Charset.forName("GBK"));
|
|
|
}
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * 解压缩zip文件到指定目录,使用指定字符集
|
|
|
- *
|
|
|
- * @param zipFilePath
|
|
|
- * @param destDir
|
|
|
- * @param charset
|
|
|
- * @throws IOException
|
|
|
+ * 按指定字符集解压ZIP文件
|
|
|
*/
|
|
|
private static void unzipWithCharset(String zipFilePath, String destDir, Charset charset) throws IOException {
|
|
|
File dir = new File(destDir);
|
|
|
- if (!dir.exists()) dir.mkdirs();
|
|
|
+ if (!dir.exists() && !dir.mkdirs()) {
|
|
|
+ throw new IOException("无法创建目录: " + destDir);
|
|
|
+ }
|
|
|
|
|
|
try (ZipFile zipFile = new ZipFile(zipFilePath, charset)) {
|
|
|
Enumeration<? extends ZipEntry> entries = zipFile.entries();
|
|
|
while (entries.hasMoreElements()) {
|
|
|
ZipEntry entry = entries.nextElement();
|
|
|
- File newFile = new File(destDir, entry.getName());
|
|
|
+ File newFile = safeNewFile(dir, entry.getName()); // 安全路径拼接
|
|
|
+
|
|
|
if (entry.isDirectory()) {
|
|
|
- newFile.mkdirs();
|
|
|
+ if (!newFile.exists() && !newFile.mkdirs()) {
|
|
|
+ throw new IOException("无法创建目录: " + newFile);
|
|
|
+ }
|
|
|
} else {
|
|
|
- new File(newFile.getParent()).mkdirs();
|
|
|
- try (InputStream is = zipFile.getInputStream(entry); FileOutputStream fos = new FileOutputStream(newFile)) {
|
|
|
- byte[] buffer = new byte[1024];
|
|
|
+ File parent = newFile.getParentFile();
|
|
|
+ if (!parent.exists() && !parent.mkdirs()) {
|
|
|
+ throw new IOException("无法创建文件目录: " + parent);
|
|
|
+ }
|
|
|
+ try (InputStream is = zipFile.getInputStream(entry);
|
|
|
+ FileOutputStream fos = new FileOutputStream(newFile)) {
|
|
|
+ byte[] buffer = new byte[4096];
|
|
|
int len;
|
|
|
while ((len = is.read(buffer)) > 0) {
|
|
|
fos.write(buffer, 0, len);
|
|
@@ -63,6 +63,19 @@ public class FileUtils {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * 防止Zip Slip漏洞:限制文件解压在目标目录内
|
|
|
+ */
|
|
|
+ private static File safeNewFile(File destinationDir, String entryName) throws IOException {
|
|
|
+ File destFile = new File(destinationDir, entryName);
|
|
|
+ String destDirPath = destinationDir.getCanonicalPath();
|
|
|
+ String destFilePath = destFile.getCanonicalPath();
|
|
|
+ if (!destFilePath.startsWith(destDirPath + File.separator)) {
|
|
|
+ throw new IOException("非法ZIP条目: " + entryName);
|
|
|
+ }
|
|
|
+ return destFile;
|
|
|
+ }
|
|
|
+
|
|
|
/**
|
|
|
* 读取文件夹中及子文件夹中的所有shp相关文件(.shp,.dbf,.prj,.qix,.shx),返回map结构,后缀名为key,文件路径为value
|
|
|
*
|