From 456b1ea62d09ff2e1db7a4940df7cfce306abae1 Mon Sep 17 00:00:00 2001 From: KodouWZF <3092554823@qq.com> Date: Tue, 3 Nov 2026 22:07:00 +0800 Subject: [PATCH] =?UTF-8?q?perf(=E4=BC=A0=E8=BE=93):=20=E5=B7=B2=E5=8E=8B?= =?UTF-8?q?=E7=BC=A9=E6=A0=BC=E5=BC=8F=E7=BB=84=E5=8C=85=E6=97=B6=E4=B8=8D?= =?UTF-8?q?=E5=86=8D=E4=BA=8C=E6=AC=A1=E5=8E=8B=E7=BC=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit pptx/docx/xlsx/zip/mp4/jpg 这类本身已压缩的格式,再跑一遍 level 6 deflate 压缩率接近 0,但 CPU 照样全量消耗(约 0.04 秒/MB)。改为按文件名后缀判断, 命中清单的 entry 用 Deflater.NO_COMPRESSION,其余保持默认 level 6。 不用 ZipEntry.STORED 是因为它要求预先提供 size 和 CRC-32,会多一遍顺序读; level 0 产出的仍是合法 zip(DEFLATE 存储块),接收端解包与校验逻辑无需改动。 清单从严,只收确定已压缩的格式,避免可压缩文件被误判导致包体变大。 元数据 JSON 可压缩,写它之前显式还原 level。 --- .../impl/TransferUserFileServiceImpl.java | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) 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)); + } }