perf(传输): 已压缩格式组包时不再二次压缩

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。
This commit is contained in:
KodouWZF
2026-11-03 22:07:00 +08:00
parent c5d19f47a2
commit 456b1ea62d

View File

@@ -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<String> 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));
}
}