diff --git a/backend/src/main/java/com/senmesh/component/file/service/storage/LocalFileStorage.java b/backend/src/main/java/com/senmesh/component/file/service/storage/LocalFileStorage.java index 67e3d43..ee722b4 100644 --- a/backend/src/main/java/com/senmesh/component/file/service/storage/LocalFileStorage.java +++ b/backend/src/main/java/com/senmesh/component/file/service/storage/LocalFileStorage.java @@ -13,6 +13,9 @@ import java.nio.file.Files; @Slf4j public class LocalFileStorage implements IFileStorage { + /** 存储目录多为 bind mount,commons-io 默认 8KB 缓冲会放大 syscall 次数 */ + private static final int COPY_BUFFER_SIZE = 64 * 1024; + @Override public void upload(InputStream is, String filePath) { File file = new File(filePath); @@ -22,8 +25,8 @@ public class LocalFileStorage implements IFileStorage { log.info("上传存储异常", e); throw new BusinessException("上传存储异常 " + e.getMessage()); } - try (OutputStream os = Files.newOutputStream(file.toPath())) { - IOUtils.copy(is, os); + try (OutputStream os = new BufferedOutputStream(Files.newOutputStream(file.toPath()), COPY_BUFFER_SIZE)) { + IOUtils.copy(is, os, COPY_BUFFER_SIZE); } catch (IOException e) { log.info("上传存储异常", e); throw new BusinessException("上传存储异常 " + e.getMessage()); diff --git a/backend/src/main/java/com/senmesh/sfile/service/impl/TransferFileMonitorServiceImpl.java b/backend/src/main/java/com/senmesh/sfile/service/impl/TransferFileMonitorServiceImpl.java index 57b8174..80f9a8f 100644 --- a/backend/src/main/java/com/senmesh/sfile/service/impl/TransferFileMonitorServiceImpl.java +++ b/backend/src/main/java/com/senmesh/sfile/service/impl/TransferFileMonitorServiceImpl.java @@ -25,6 +25,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import java.io.BufferedInputStream; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.FileInputStream; @@ -53,6 +54,9 @@ import java.util.zip.ZipInputStream; @Slf4j public class TransferFileMonitorServiceImpl implements TransferFileMonitorService { + /** 接收目录多为 bind mount,单次 syscall 成本可达毫秒级,小缓冲会把耗时放大数十倍 */ + private static final int TRANSFER_BUFFER_SIZE = 64 * 1024; + @Autowired private FileProperties fileProperties; @@ -409,7 +413,8 @@ public class TransferFileMonitorServiceImpl implements TransferFileMonitorServic } // 4. 解析 ZIP 文件,上传文件并设置 fileCode - try (ZipInputStream zis = new ZipInputStream(new FileInputStream(zipFilePath.toFile()))) { + try (ZipInputStream zis = new ZipInputStream( + new BufferedInputStream(new FileInputStream(zipFilePath.toFile()), TRANSFER_BUFFER_SIZE))) { ZipEntry entry; while ((entry = zis.getNextEntry()) != null) { // 跳过元数据文件和目录 @@ -444,7 +449,7 @@ public class TransferFileMonitorServiceImpl implements TransferFileMonitorServic // 读取文件流到内存 ByteArrayOutputStream baos = new ByteArrayOutputStream(); - byte[] buffer = new byte[8192]; + byte[] buffer = new byte[TRANSFER_BUFFER_SIZE]; int len; while ((len = zis.read(buffer)) > 0) { baos.write(buffer, 0, len); 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 5a0c925..ac1dc3d 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 @@ -23,6 +23,8 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import java.io.BufferedInputStream; +import java.io.BufferedOutputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; @@ -40,6 +42,9 @@ import java.util.zip.ZipOutputStream; @Slf4j public class TransferUserFileServiceImpl implements TransferUserFileService { + /** 传输目录多为 bind mount,单次 syscall 成本可达毫秒级,小缓冲会把耗时放大数十倍 */ + private static final int TRANSFER_BUFFER_SIZE = 64 * 1024; + @Autowired private UserFileService userFileService; @@ -122,7 +127,10 @@ public class TransferUserFileServiceImpl implements TransferUserFileService { String finalFileName = folder.getUserId() + "_" + folder.getId() + ".zip"; Path finalFilePath = transferPath.resolve(finalFileName); - try (ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(finalFilePath.toFile()))) { + // ZipOutputStream 的内部 deflate 输出缓冲在 JDK8 中硬编码为 512 字节且不可配置, + // 必须在外层用 BufferedOutputStream 兜住,凑满 64KB 再落盘 + try (ZipOutputStream zos = new ZipOutputStream( + new BufferedOutputStream(new FileOutputStream(finalFilePath.toFile()), TRANSFER_BUFFER_SIZE))) { // 2.1 添加文件夹中的文件 String folderName = folder.getFileName(); for (UserFileDTO file : files) { @@ -135,8 +143,8 @@ public class TransferUserFileServiceImpl implements TransferUserFileService { zos.putNextEntry(zipEntry); // 边读边写 - try (InputStream inputStream = fileService.getFile(fileCode)) { - byte[] buffer = new byte[8192]; + try (InputStream inputStream = new BufferedInputStream(fileService.getFile(fileCode), TRANSFER_BUFFER_SIZE)) { + byte[] buffer = new byte[TRANSFER_BUFFER_SIZE]; int len; while ((len = inputStream.read(buffer)) > 0) { zos.write(buffer, 0, len);