diff --git a/java/src/main/java/com/yfd/platform/modules/experimentalData/service/impl/TsFilesServiceImpl.java b/java/src/main/java/com/yfd/platform/modules/experimentalData/service/impl/TsFilesServiceImpl.java index 6c779b8..9fab438 100644 --- a/java/src/main/java/com/yfd/platform/modules/experimentalData/service/impl/TsFilesServiceImpl.java +++ b/java/src/main/java/com/yfd/platform/modules/experimentalData/service/impl/TsFilesServiceImpl.java @@ -43,28 +43,15 @@ import com.yfd.platform.system.domain.SysDictionaryItems; import com.yfd.platform.system.mapper.SysDictionaryItemsMapper; import com.yfd.platform.utils.StringUtils; import io.netty.channel.ChannelInboundHandlerAdapter; -import com.github.junrar.Archive; -import com.github.junrar.rarfile.FileHeader; -import com.github.junrar.exception.RarException; -import io.netty.handler.codec.compression.CompressionException; -import org.apache.commons.compress.archivers.ArchiveEntry; -import org.apache.commons.compress.archivers.ArchiveOutputStream; import org.apache.commons.compress.archivers.sevenz.SevenZArchiveEntry; import org.apache.commons.compress.archivers.sevenz.SevenZFile; -import org.apache.commons.compress.archivers.sevenz.SevenZOutputFile; import org.apache.commons.compress.archivers.tar.TarArchiveEntry; import org.apache.commons.compress.archivers.tar.TarArchiveInputStream; import org.apache.commons.compress.archivers.tar.TarArchiveOutputStream; import org.apache.commons.compress.archivers.zip.ZipArchiveEntry; -import org.apache.commons.compress.archivers.zip.ZipArchiveInputStream; import org.apache.commons.compress.archivers.zip.ZipArchiveOutputStream; -import org.apache.commons.compress.compressors.bzip2.BZip2CompressorInputStream; -import org.apache.commons.compress.compressors.bzip2.BZip2CompressorOutputStream; import org.apache.commons.compress.compressors.gzip.GzipCompressorInputStream; import org.apache.commons.compress.compressors.gzip.GzipCompressorOutputStream; -import org.apache.commons.compress.compressors.xz.XZCompressorOutputStream; -import org.apache.commons.io.FileUtils; -import org.apache.commons.io.FilenameUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; @@ -115,6 +102,7 @@ public class TsFilesServiceImpl extends ServiceImpl impl // 从数据库获取的压缩类型列表 private List compressSuffixes; + private final Set addedEntries = new HashSet<>(); /********************************** * 用途说明: 分页查询试验数据管理-文档内容 @@ -1167,13 +1155,18 @@ public class TsFilesServiceImpl extends ServiceImpl impl } Path zipPath = generateZipPath(sourcePaths.get(0)); + addedEntries.clear(); // 清空历史记录 + try (ZipOutputStream zipOut = new ZipOutputStream(Files.newOutputStream(zipPath))) { zipOut.setLevel(Deflater.DEFAULT_COMPRESSION); for (Path sourcePath : sourcePaths) { if (Files.isDirectory(sourcePath)) { - addDirectoryToZip(sourcePath, zipOut, sourcePath.getFileName().toString()); + // 使用唯一化的 baseDir(例如目录名) + String baseDir = sourcePath.getFileName().toString(); + addDirectoryToZip(sourcePath, zipOut, baseDir); } else { + // 文件直接添加到根目录,或指定唯一子目录 addFileToZip(sourcePath, zipOut, ""); } } @@ -1188,23 +1181,46 @@ public class TsFilesServiceImpl extends ServiceImpl impl } private void addDirectoryToZip(Path dir, ZipOutputStream zipOut, String baseDir) throws IOException { + final Path sourceDir = dir; + Files.walkFileTree(dir, new SimpleFileVisitor() { @Override - public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException { - String entryName = baseDir + "/" + dir.relativize(dir).toString().replace("\\", "/") + "/"; - ZipEntry entry = new ZipEntry(entryName); - zipOut.putNextEntry(entry); - zipOut.closeEntry(); + public FileVisitResult preVisitDirectory(Path currentDir, BasicFileAttributes attrs) throws IOException { + // 跳过源目录自身(由外部显式添加) + if (currentDir.equals(sourceDir)) { + return FileVisitResult.CONTINUE; + } + + // 生成相对路径的条目名称 + Path relativePath = sourceDir.relativize(currentDir); + String entryName = baseDir + "/" + relativePath.toString().replace("\\", "/") + "/"; + + // 确保条目唯一性 + addUniqueDirectoryEntry(entryName, zipOut); return FileVisitResult.CONTINUE; } @Override public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { - String entryName = baseDir + "/" + dir.relativize(file).toString().replace("\\", "/"); + Path relativePath = sourceDir.relativize(file); + String entryName = baseDir + "/" + relativePath.toString().replace("\\", "/"); addFileEntry(file, entryName, zipOut); return FileVisitResult.CONTINUE; } }); + + // 显式添加根目录条目(确保至少存在一个目录条目) + String rootEntry = baseDir + "/"; + addUniqueDirectoryEntry(rootEntry, zipOut); + } + + private void addUniqueDirectoryEntry(String entryName, ZipOutputStream zipOut) throws IOException { + if (!addedEntries.contains(entryName)) { + ZipEntry entry = new ZipEntry(entryName); + zipOut.putNextEntry(entry); + zipOut.closeEntry(); + addedEntries.add(entryName); + } } private void addFileToZip(Path file, ZipOutputStream zipOut, String baseDir) throws IOException { @@ -1213,6 +1229,11 @@ public class TsFilesServiceImpl extends ServiceImpl impl } private void addFileEntry(Path file, String entryName, ZipOutputStream zipOut) throws IOException { + if (addedEntries.contains(entryName)) { + LOGGER.warn("跳过重复条目: {}", entryName); + return; + } + LOGGER.debug("添加文件条目: {} (大小: {} 字节)", entryName, Files.size(file)); ZipEntry entry = new ZipEntry(entryName); entry.setSize(Files.size(file)); @@ -1228,6 +1249,7 @@ public class TsFilesServiceImpl extends ServiceImpl impl } zipOut.closeEntry(); + addedEntries.add(entryName); } private Path generateZipPath(Path sourcePath) { @@ -1247,7 +1269,8 @@ public class TsFilesServiceImpl extends ServiceImpl impl ZipEntry entry = entries.nextElement(); try (InputStream is = zipFile.getInputStream(entry)) { byte[] buffer = new byte[1024]; - while (is.read(buffer) != -1) {} // 读取条目内容 + while (is.read(buffer) != -1) { + } // 读取条目内容 } } @@ -1262,7 +1285,8 @@ public class TsFilesServiceImpl extends ServiceImpl impl private void deleteQuietly(Path path) { try { Files.deleteIfExists(path); - } catch (IOException ignored) {} + } catch (IOException ignored) { + } } /** @@ -1277,13 +1301,6 @@ public class TsFilesServiceImpl extends ServiceImpl impl } - - - - - - - // ================== TAR.GZ格式压缩实现 ================== private boolean compressToTarGz(List sourcePaths) throws IOException { boolean success = true; @@ -1420,7 +1437,7 @@ public class TsFilesServiceImpl extends ServiceImpl impl // 1. 获取压缩包记录 TsFiles zipFileRecord = tsFilesMapper.selectById(id); - String zipName = zipFileRecord.getFileName(); // 示例:222 + String zipName = getFileNameWithoutExtension(zipFileRecord.getFileName()); // 示例:222 try { // 2. 判断压缩包类型(单文件还是文件夹) Path zipFilePath = Paths.get(storageSourceConfig.getValue(), zipFileRecord.getWorkPath(), zipFileRecord.getFileName()); @@ -1429,12 +1446,8 @@ public class TsFilesServiceImpl extends ServiceImpl impl // // 4. 构建解压目标路径 Path destRoot; if (hasFolder) { - // 动态去掉 .zip 后缀(仅用于路径构建) - String folderName = zipName.toLowerCase().endsWith(".zip") - ? zipName.substring(0, zipName.length() - 4) - : zipName; // 如果有文件夹,创建子目录(如 E:/yun/333/222/) - destRoot = Paths.get(storageSourceConfig.getValue(), decompressionPath, folderName); + destRoot = Paths.get(storageSourceConfig.getValue(), decompressionPath, zipName); } else { // 如果只有文件,直接解压到目标目录(如 E:/yun/333/) destRoot = Paths.get(storageSourceConfig.getValue(), decompressionPath); @@ -1460,7 +1473,7 @@ public class TsFilesServiceImpl extends ServiceImpl impl ); String rootFolderId = rootFolder.getId(); - // 7. 处理子内容(路径从/333/222/开始) + // 7. 处理子内容(路径从/333/222/开始) 关键点 所有的文件夹都是上级路径 文件是上级路径加名称 processFolderContents( unzippedRoot, rootFolderId, @@ -1577,7 +1590,7 @@ public class TsFilesServiceImpl extends ServiceImpl impl folderRecord.setTaskId(taskId); folderRecord.setParentId(parentId); // 父ID是222的ID folderRecord.setFileName(child.getName()); - folderRecord.setWorkPath(childWorkPath); // /333/222/555/ + folderRecord.setWorkPath(folderWorkPath); // /333/222/555/ folderRecord.setIsFile("FOLDER"); folderRecord.setFileSize("0"); folderRecord.setUploadTime(new Timestamp(System.currentTimeMillis())); @@ -1587,7 +1600,7 @@ public class TsFilesServiceImpl extends ServiceImpl impl processFolderContents( child, folderRecord.getId(), - folderWorkPath, + childWorkPath, taskId, nodeId, uploader