|
@@ -4,26 +4,28 @@ import cn.hutool.core.collection.ListUtil;
|
|
import cn.hutool.core.io.FileUtil;
|
|
import cn.hutool.core.io.FileUtil;
|
|
import cn.hutool.core.util.StrUtil;
|
|
import cn.hutool.core.util.StrUtil;
|
|
import com.smppw.modaq.common.enums.ReportType;
|
|
import com.smppw.modaq.common.enums.ReportType;
|
|
-import net.sf.sevenzipjbinding.ExtractOperationResult;
|
|
|
|
-import net.sf.sevenzipjbinding.IInArchive;
|
|
|
|
-import net.sf.sevenzipjbinding.SevenZip;
|
|
|
|
-import net.sf.sevenzipjbinding.SevenZipException;
|
|
|
|
|
|
+import net.sf.sevenzipjbinding.*;
|
|
import net.sf.sevenzipjbinding.impl.RandomAccessFileInStream;
|
|
import net.sf.sevenzipjbinding.impl.RandomAccessFileInStream;
|
|
import net.sf.sevenzipjbinding.simple.ISimpleInArchive;
|
|
import net.sf.sevenzipjbinding.simple.ISimpleInArchive;
|
|
import net.sf.sevenzipjbinding.simple.ISimpleInArchiveItem;
|
|
import net.sf.sevenzipjbinding.simple.ISimpleInArchiveItem;
|
|
import org.apache.commons.compress.archivers.ArchiveEntry;
|
|
import org.apache.commons.compress.archivers.ArchiveEntry;
|
|
-import org.apache.commons.compress.archivers.ArchiveException;
|
|
|
|
import org.apache.commons.compress.archivers.ArchiveInputStream;
|
|
import org.apache.commons.compress.archivers.ArchiveInputStream;
|
|
import org.apache.commons.compress.archivers.ArchiveStreamFactory;
|
|
import org.apache.commons.compress.archivers.ArchiveStreamFactory;
|
|
|
|
+import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
|
|
|
|
+import org.apache.commons.compress.archivers.zip.ZipFile;
|
|
|
|
+import org.apache.commons.io.IOUtils;
|
|
|
|
|
|
import java.io.*;
|
|
import java.io.*;
|
|
import java.nio.charset.Charset;
|
|
import java.nio.charset.Charset;
|
|
import java.nio.file.Files;
|
|
import java.nio.file.Files;
|
|
|
|
+import java.nio.file.Path;
|
|
|
|
+import java.nio.file.Paths;
|
|
import java.util.Arrays;
|
|
import java.util.Arrays;
|
|
|
|
+import java.util.Enumeration;
|
|
import java.util.List;
|
|
import java.util.List;
|
|
import java.util.regex.Pattern;
|
|
import java.util.regex.Pattern;
|
|
|
|
|
|
-public class ExcelUtil {
|
|
|
|
|
|
+public class ArchiveUtil {
|
|
// 候选编码列表(按常见顺序排列)
|
|
// 候选编码列表(按常见顺序排列)
|
|
private static final List<String> CANDIDATE_ENCODINGS = Arrays.asList(
|
|
private static final List<String> CANDIDATE_ENCODINGS = Arrays.asList(
|
|
"GBK", // 中文环境常用
|
|
"GBK", // 中文环境常用
|
|
@@ -50,27 +52,15 @@ public class ExcelUtil {
|
|
{0x3000, 0x303F} // 常用标点
|
|
{0x3000, 0x303F} // 常用标点
|
|
};
|
|
};
|
|
|
|
|
|
- public static boolean isExcel(String fileName) {
|
|
|
|
- return StrUtil.isNotBlank(fileName) && (fileName.endsWith("xls") || fileName.endsWith("xlsx") || fileName.endsWith("XLS") || fileName.endsWith("XLSX"));
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- public static boolean isPdf(String fileName) {
|
|
|
|
- return StrUtil.isNotBlank(fileName) && (fileName.endsWith("pdf") || fileName.endsWith("PDF"));
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
public static boolean isZip(String fileName) {
|
|
public static boolean isZip(String fileName) {
|
|
return StrUtil.isNotBlank(fileName) && (fileName.endsWith("zip") || fileName.endsWith("ZIP"));
|
|
return StrUtil.isNotBlank(fileName) && (fileName.endsWith("zip") || fileName.endsWith("ZIP"));
|
|
}
|
|
}
|
|
|
|
|
|
- public static boolean isHTML(String fileName) {
|
|
|
|
- return StrUtil.isNotBlank(fileName) && fileName.endsWith("html");
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
public static boolean isRAR(String fileName) {
|
|
public static boolean isRAR(String fileName) {
|
|
return StrUtil.isNotBlank(fileName) && (fileName.endsWith("rar") || fileName.endsWith("RAR"));
|
|
return StrUtil.isNotBlank(fileName) && (fileName.endsWith("rar") || fileName.endsWith("RAR"));
|
|
}
|
|
}
|
|
|
|
|
|
- public static List<String> extractCompressedFiles(String zipFilePath, String destFilePath) throws IOException, ArchiveException {
|
|
|
|
|
|
+ public static List<String> extractCompressedFiles(String zipFilePath, String destFilePath) throws IOException {
|
|
File destFile = FileUtil.file(destFilePath);
|
|
File destFile = FileUtil.file(destFilePath);
|
|
if (!destFile.exists()) {
|
|
if (!destFile.exists()) {
|
|
Files.createDirectories(destFile.toPath());
|
|
Files.createDirectories(destFile.toPath());
|
|
@@ -81,12 +71,15 @@ public class ExcelUtil {
|
|
encoding = "GBK";
|
|
encoding = "GBK";
|
|
}
|
|
}
|
|
|
|
|
|
- return ZipUtil.decompressZip(zipFilePath, destFilePath, 2, encoding);
|
|
|
|
|
|
+ return decompressZip(zipFilePath, destFilePath, 2, encoding);
|
|
}
|
|
}
|
|
|
|
|
|
- public static List<String> extractRar5(String rarFilePath, String outputDir) throws Exception {
|
|
|
|
- // 初始化 SevenZipJBinding 本地库
|
|
|
|
- SevenZip.initSevenZipFromPlatformJAR();
|
|
|
|
|
|
+ public static List<String> extractRar5(String rarFilePath, String outputDir) throws IOException {
|
|
|
|
+ try {
|
|
|
|
+ // 初始化 SevenZipJBinding 本地库
|
|
|
|
+ SevenZip.initSevenZipFromPlatformJAR();
|
|
|
|
+ } catch (SevenZipNativeInitializationException ignored) {
|
|
|
|
+ }
|
|
|
|
|
|
RandomAccessFile randomAccessFile = null;
|
|
RandomAccessFile randomAccessFile = null;
|
|
IInArchive inArchive = null;
|
|
IInArchive inArchive = null;
|
|
@@ -250,6 +243,114 @@ public class ExcelUtil {
|
|
return true;
|
|
return true;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ /**
|
|
|
|
+ * 递归解压 ZIP 文件(含嵌套深度限制)
|
|
|
|
+ *
|
|
|
|
+ * @param zipFile 输入的 ZIP 文件
|
|
|
|
+ * @param outputDir 解压目标根目录
|
|
|
|
+ * @param maxDepth 最大嵌套深度(例如 3 表示允许 parent/nest1/nest2.zip)
|
|
|
|
+ * @return 所有解压后的文件路径(格式:parent.zip/nest1/file.txt)
|
|
|
|
+ */
|
|
|
|
+ public static List<String> decompressZip(String zipFile, String outputDir, int maxDepth, String encoding) throws IOException {
|
|
|
|
+ return decompressZip(FileUtil.file(zipFile), FileUtil.file(outputDir), maxDepth, encoding);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * 递归解压 ZIP 文件(含嵌套深度限制)
|
|
|
|
+ *
|
|
|
|
+ * @param zipFile 输入的 ZIP 文件
|
|
|
|
+ * @param outputDir 解压目标根目录
|
|
|
|
+ * @param maxDepth 最大嵌套深度(例如 3 表示允许 parent.zip/nest1.zip/nest2.zip)
|
|
|
|
+ * @return 所有解压后的文件路径(格式:parent.zip/nest1.zip/file.txt)
|
|
|
|
+ */
|
|
|
|
+ public static List<String> decompressZip(File zipFile, File outputDir, int maxDepth, String encoding) throws IOException {
|
|
|
|
+ if (maxDepth < 0) {
|
|
|
|
+ throw new IllegalArgumentException("最大嵌套深度不能小于 0");
|
|
|
|
+ }
|
|
|
|
+ List<String> decompressedFiles = ListUtil.list(false);
|
|
|
|
+ decompressZipRecursive(zipFile, outputDir, "", 0, maxDepth, encoding, decompressedFiles);
|
|
|
|
+ return decompressedFiles;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * 递归解压核心逻辑
|
|
|
|
+ */
|
|
|
|
+ private static void decompressZipRecursive(
|
|
|
|
+ File currentZip,
|
|
|
|
+ File rootOutputDir,
|
|
|
|
+ String nestedPath,
|
|
|
|
+ int currentDepth,
|
|
|
|
+ int maxDepth,
|
|
|
|
+ String encoding,
|
|
|
|
+ List<String> decompressedFiles) throws IOException {
|
|
|
|
+
|
|
|
|
+ // 1. 超过最大深度时停止处理嵌套 ZIP
|
|
|
|
+ if (currentDepth > maxDepth) {
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // 2. 创建当前 ZIP 的解压目录(跟压缩包目录已经处理过,就不要追加到文件目录中了)
|
|
|
|
+ String currentZipName = FileUtil.mainName(currentZip);
|
|
|
|
+ String currentNestedPath = nestedPath.isEmpty()
|
|
|
|
+ ? ""
|
|
|
|
+ : nestedPath + File.separator + currentZipName;
|
|
|
|
+ File currentOutputDir = new File(rootOutputDir, currentNestedPath);
|
|
|
|
+ FileUtil.mkdir(currentOutputDir);
|
|
|
|
+
|
|
|
|
+ // 3. 解压当前 ZIP,支持最多10个分卷的解压
|
|
|
|
+ try (ZipFile zip = ZipFile.builder().setFile(currentZip).setCharset(encoding).setMaxNumberOfDisks(10).get()) {
|
|
|
|
+ Enumeration<ZipArchiveEntry> entries = zip.getEntries();
|
|
|
|
+
|
|
|
|
+ while (entries.hasMoreElements()) {
|
|
|
|
+ ZipArchiveEntry entry = entries.nextElement();
|
|
|
|
+ String name = entry.getName();
|
|
|
|
+ if (name.startsWith("__MACOSX/")) {
|
|
|
|
+ continue;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ Path entryPath = Paths.get(currentOutputDir.getAbsolutePath(), name);
|
|
|
|
+
|
|
|
|
+ // 处理目录
|
|
|
|
+ if (entry.isDirectory()) {
|
|
|
|
+ Files.createDirectories(entryPath);
|
|
|
|
+ continue;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // 写入文件
|
|
|
|
+ Files.createDirectories(entryPath.getParent());
|
|
|
|
+ try (InputStream is = zip.getInputStream(entry);
|
|
|
|
+ OutputStream os = new FileOutputStream(entryPath.toFile())) {
|
|
|
|
+ IOUtils.copy(is, os);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // 4. 递归处理嵌套 ZIP(深度+1)
|
|
|
|
+ if (isZipFile(name) && currentDepth < maxDepth) {
|
|
|
|
+ File nestedZipFile = entryPath.toFile();
|
|
|
|
+ decompressZipRecursive(
|
|
|
|
+ nestedZipFile,
|
|
|
|
+ rootOutputDir,
|
|
|
|
+ currentNestedPath,
|
|
|
|
+ currentDepth + 1, // 深度递增
|
|
|
|
+ maxDepth,
|
|
|
|
+ encoding,
|
|
|
|
+ decompressedFiles
|
|
|
|
+ );
|
|
|
|
+ Files.delete(nestedZipFile.toPath());
|
|
|
|
+ } else {
|
|
|
|
+ // 记录路径
|
|
|
|
+ decompressedFiles.add(entryPath.toString());
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * 判断文件是否为 ZIP 格式
|
|
|
|
+ */
|
|
|
|
+ private static boolean isZipFile(String filepath) {
|
|
|
|
+ return filepath.toLowerCase().endsWith(".zip");
|
|
|
|
+ }
|
|
|
|
+
|
|
public static void main(String[] args) throws Exception {
|
|
public static void main(String[] args) throws Exception {
|
|
String zipFilePath = "D:\\home\\wwwroot\\mo_report_file\\wangzaijun@simuwang.com\\20250321\\20250321143709排排网确认单.rar";
|
|
String zipFilePath = "D:\\home\\wwwroot\\mo_report_file\\wangzaijun@simuwang.com\\20250321\\20250321143709排排网确认单.rar";
|
|
String destFilePath = "D:\\home\\wwwroot\\mo_report_file\\wangzaijun@simuwang.com\\20250321";
|
|
String destFilePath = "D:\\home\\wwwroot\\mo_report_file\\wangzaijun@simuwang.com\\20250321";
|
|
@@ -261,5 +362,10 @@ public class ExcelUtil {
|
|
// for (String s : fileList) {
|
|
// for (String s : fileList) {
|
|
// System.out.println(s);
|
|
// System.out.println(s);
|
|
// }
|
|
// }
|
|
|
|
+
|
|
|
|
+ String currentZip = "D:\\Documents\\新报告解析\\确认单\\20250514_份额及交易确认函_上海量魁私募基金管理有限公司_深圳市前海排排网基金销售有限责任公司_TA确认数据.zip";
|
|
|
|
+ List<String> files = decompressZip(currentZip, "D:\\Documents\\新报告解析\\确认单\\", 2, "utf-8");
|
|
|
|
+ System.out.println("解压后的文件路径:");
|
|
|
|
+ files.forEach(System.out::println);
|
|
}
|
|
}
|
|
}
|
|
}
|