package com.smppw.modaq.infrastructure.util; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.collection.ListUtil; import cn.hutool.core.io.FileUtil; import cn.hutool.core.util.StrUtil; import net.sf.sevenzipjbinding.ExtractOperationResult; import net.sf.sevenzipjbinding.IInArchive; import net.sf.sevenzipjbinding.SevenZip; import net.sf.sevenzipjbinding.SevenZipException; import net.sf.sevenzipjbinding.impl.RandomAccessFileInStream; import net.sf.sevenzipjbinding.simple.ISimpleInArchive; import net.sf.sevenzipjbinding.simple.ISimpleInArchiveItem; 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.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.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.util.Arrays; import java.util.Enumeration; import java.util.List; public class ExcelUtil { // 候选编码列表(按常见顺序排列) private static final List CANDIDATE_ENCODINGS = Arrays.asList( "GBK", // 中文环境常用 "UTF-8", // 标准编码 "GB2312", // 旧版中文 "ISO-8859-1" // 默认回退 ); 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) { 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) { return StrUtil.isNotBlank(fileName) && (fileName.endsWith("rar") || fileName.endsWith("RAR")); } public static List extractCompressedFiles(String zipFilePath, String destFilePath) throws IOException, ArchiveException { List filePathList = CollUtil.newArrayList(); File destFile = FileUtil.file(destFilePath); if (!destFile.exists()) { Files.createDirectories(destFile.toPath()); } String encoding = detectEncoding(zipFilePath); if (encoding == null) { encoding = "GBK"; } try (BufferedInputStream fis = new BufferedInputStream(new FileInputStream(zipFilePath)); ArchiveInputStream ais = new ArchiveStreamFactory() .createArchiveInputStream(ArchiveStreamFactory.detect(fis), fis, encoding)) { ArchiveEntry entry; while ((entry = ais.getNextEntry()) != null) { String name = entry.getName(); if (entry.isDirectory()) { File entryFile = FileUtil.file(destFilePath, name); Files.createDirectories(entryFile.toPath()); } else { if (name.startsWith("__MACOSX/")) { continue; } String zipFilename = FileUtil.getName(destFilePath); if (zipFilename.contains("确认") && !name.contains("确认")) { String ext = FileUtil.extName(name); name = StrUtil.subBefore(name, ".", true); name = name + "_确认单." + ext; } File entryFile = FileUtil.file(destFilePath, name); try (FileOutputStream fos = new FileOutputStream(entryFile)) { IOUtils.copy(ais, fos); filePathList.add(entryFile.getPath()); } } } } catch (Exception e) { if (e.getMessage() != null && (e.getMessage().contains("split") || e.getMessage().contains("volume"))) { filePathList.addAll(extractSplitZip(zipFilePath, destFilePath, encoding)); } else { throw e; } } return filePathList; } public static List extractSplitZip(String zipFilePath, String destFilePath, String encoding) throws IOException { List resultList = ListUtil.list(false); File file = new File(zipFilePath); try (ZipFile zipFile = ZipFile.builder().setFile(file).setCharset(encoding).get()) { Enumeration entries = zipFile.getEntries(); while (entries.hasMoreElements()) { ZipArchiveEntry entry = entries.nextElement(); // 解压到目标目录 try (InputStream is = zipFile.getInputStream(entry)) { Path path = Paths.get(destFilePath, entry.getName()); FileUtil.del(path); Files.copy(is, path); resultList.add(path.toAbsolutePath().toString()); } } } return resultList; } public static List extractRar5(String rarFilePath, String outputDir) throws Exception { // 初始化 SevenZipJBinding 本地库 SevenZip.initSevenZipFromPlatformJAR(); RandomAccessFile randomAccessFile = null; IInArchive inArchive = null; List resultList = ListUtil.list(false); try { // 打开 RAR 文件 randomAccessFile = new RandomAccessFile(rarFilePath, "r"); inArchive = SevenZip.openInArchive(null, new RandomAccessFileInStream(randomAccessFile)); // 获取压缩包中的文件列表 ISimpleInArchive simpleInArchive = inArchive.getSimpleInterface(); for (ISimpleInArchiveItem item : simpleInArchive.getArchiveItems()) { if (!item.isFolder()) { resultList.add(extractItem(item, outputDir)); } } } finally { // 释放资源 if (inArchive != null) { inArchive.close(); } if (randomAccessFile != null) { randomAccessFile.close(); } } return resultList; } private static String extractItem(ISimpleInArchiveItem item, String outputDir) throws SevenZipException { String filePath = outputDir + File.separator + item.getPath(); File outputFile = FileUtil.file(filePath); // 创建父目录 File parentDir = outputFile.getParentFile(); if (!parentDir.exists() && !parentDir.mkdirs()) { throw new SevenZipException("无法创建目录: " + parentDir.getAbsolutePath()); } // 提取文件内容 try (FileOutputStream fos = new FileOutputStream(outputFile)) { ExtractOperationResult result = item.extractSlow(data -> { try { fos.write(data); return data.length; // 返回写入的字节数 } catch (IOException e) { throw new SevenZipException("写入文件失败", e); } }); if (result != ExtractOperationResult.OK) { throw new SevenZipException("解压失败: " + result); } } catch (IOException e) { throw new SevenZipException("文件操作失败", e); } return outputFile.getAbsolutePath(); } // 检测压缩包编码 private static String detectEncoding(String zipPath) { for (String encoding : CANDIDATE_ENCODINGS) { try (BufferedInputStream fis = new BufferedInputStream(new FileInputStream(zipPath)); ArchiveInputStream ais = new ArchiveStreamFactory() .createArchiveInputStream(ArchiveStreamFactory.detect(fis), fis, encoding)) { ArchiveEntry entry = ais.getNextEntry(); if (entry == null) continue; // 空压缩包 String fileName = entry.getName(); if (!hasInvalidCharacters(fileName)) { return encoding; // 找到有效编码 } } catch (Exception e) { // 编码不支持或文件错误,继续尝试下一个 } } return null; } // 检查文件名是否包含无效字符(如替换符) private static boolean hasInvalidCharacters(String fileName) { // 检查常见乱码符号:�或连续问号 return fileName.contains("�") || fileName.matches(".*\\?{2,}.*"); } public static void main(String[] args) throws Exception { 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"; List strings = extractRar5(zipFilePath, destFilePath); for (String string : strings) { System.out.println(string); } // List fileList = extractCompressedFiles(zipFilePath, destFilePath); // for (String s : fileList) { // System.out.println(s); // } } }