diff --git a/backend/src/main/java/com/senmesh/sfile/service/impl/TransferUserFileServiceImpl.java b/backend/src/main/java/com/senmesh/sfile/service/impl/TransferUserFileServiceImpl.java index ac1dc3d..e4fc396 100644 --- a/backend/src/main/java/com/senmesh/sfile/service/impl/TransferUserFileServiceImpl.java +++ b/backend/src/main/java/com/senmesh/sfile/service/impl/TransferUserFileServiceImpl.java @@ -1,5 +1,6 @@ package com.senmesh.sfile.service.impl; +import com.google.common.collect.ImmutableSet; import com.senmesh.common.exception.util.Assert; import com.senmesh.common.util.JsonUtils; import com.senmesh.common.util.UserContextHolder; @@ -32,6 +33,9 @@ import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.util.List; +import java.util.Locale; +import java.util.Set; +import java.util.zip.Deflater; import java.util.zip.ZipEntry; import java.util.zip.ZipOutputStream; @@ -45,6 +49,14 @@ public class TransferUserFileServiceImpl implements TransferUserFileService { /** 传输目录多为 bind mount,单次 syscall 成本可达毫秒级,小缓冲会把耗时放大数十倍 */ private static final int TRANSFER_BUFFER_SIZE = 64 * 1024; + /** 本身已压缩的格式再跑一遍 deflate 压缩率接近 0,但 CPU 照样全量消耗,故存原样。清单从严,只收确定已压缩的 */ + private static final Set PRE_COMPRESSED_SUFFIXES = ImmutableSet.of( + "zip", "rar", "7z", "gz", "tgz", "bz2", "xz", "jar", "war", "apk", + "docx", "xlsx", "pptx", "odt", "ods", "odp", "vsdx", + "jpg", "jpeg", "png", "gif", "webp", + "mp4", "avi", "mkv", "mov", "wmv", "flv", "mpg", "mpeg", "webm", + "mp3", "aac", "flac", "ogg"); + @Autowired private UserFileService userFileService; @@ -139,6 +151,9 @@ public class TransferUserFileServiceImpl implements TransferUserFileService { // 创建 ZipEntry(使用 userFileId 命名) String entryName = folderName + "/" + userFileId; + zos.setLevel(isPreCompressed(file.getFileName()) + ? Deflater.NO_COMPRESSION + : Deflater.DEFAULT_COMPRESSION); ZipEntry zipEntry = new ZipEntry(entryName); zos.putNextEntry(zipEntry); @@ -166,6 +181,8 @@ public class TransferUserFileServiceImpl implements TransferUserFileService { String metadataJson = JsonUtils.toJsonString(metadata); ZipEntry metadataEntry = new ZipEntry("transferMetadata.json"); + // 上一个文件可能把 level 置成了 0,JSON 元数据可压缩,需还原 + zos.setLevel(Deflater.DEFAULT_COMPRESSION); zos.putNextEntry(metadataEntry); zos.write(metadataJson.getBytes("UTF-8")); zos.closeEntry(); @@ -173,4 +190,15 @@ public class TransferUserFileServiceImpl implements TransferUserFileService { log.info("传输文件打包完成: {}", finalFilePath); } + + private boolean isPreCompressed(String fileName) { + if (fileName == null) { + return false; + } + int dot = fileName.lastIndexOf('.'); + if (dot < 0 || dot == fileName.length() - 1) { + return false; + } + return PRE_COMPRESSED_SUFFIXES.contains(fileName.substring(dot + 1).toLowerCase(Locale.ROOT)); + } }