You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用Spring构建端点流式处理大文件,避免全量加载至内存?

大文件流式上传与下载实现方案

关于MultipartFile转流的内存疑问

明确结论:MultipartFile是否会将文件加载到内存,取决于文件大小和框架配置。以Spring Boot为例,当文件大小小于spring.servlet.multipart.file-size-threshold(默认1MB)时,文件会被缓存到内存;超过这个阈值,框架会自动将文件写入磁盘临时文件,此时调用getInputStream()获取的流是直接从磁盘读取的,不会把整个大文件加载到内存。只要配置合理,转流操作不会导致大文件驻留内存。

流式上传实现

核心逻辑是逐块读取请求中的文件流,直接写入目标存储(磁盘/对象存储),全程仅用固定大小的缓冲区缓存数据,避免全量加载文件到内存。

Spring Boot 示例代码

@PostMapping("/upload")
public ResponseEntity<String> uploadFile(@RequestParam("file") MultipartFile file) throws IOException {
    // 替换为实际的目标存储输出流(如磁盘文件、对象存储流)
    try (InputStream inputStream = file.getInputStream();
         OutputStream outputStream = new FileOutputStream("/storage/target/" + file.getOriginalFilename())) {
        
        // 缓冲区大小可根据服务器性能调整,推荐8KB~64KB
        byte[] buffer = new byte[8192];
        int bytesRead;
        // 逐块读写,每次仅加载缓冲区大小的数据到内存
        while ((bytesRead = inputStream.read(buffer)) != -1) {
            outputStream.write(buffer, 0, bytesRead);
        }
    }
    return ResponseEntity.ok("文件上传完成");
}
  • 配置优化:在application.yml中调整Multipart参数,确保大文件自动落地磁盘:
spring:
  servlet:
    multipart:
      max-file-size: 2GB  # 允许单个文件最大大小
      max-request-size: 2GB # 允许整个请求的总大小
      file-size-threshold: 1MB # 超过此大小的文件写入临时磁盘

流式下载实现

核心是直接从存储读取文件流,逐块输出到响应体,不将整个文件加载到内存。

Spring Boot 示例代码

@GetMapping("/download/{fileName}")
public ResponseEntity<Resource> downloadFile(@PathVariable String fileName) throws IOException {
    File targetFile = new File("/storage/source/" + fileName);
    if (!targetFile.exists()) {
        return ResponseEntity.notFound().build();
    }

    // 用InputStreamResource包装文件流,Spring MVC会自动流式输出
    InputStreamResource resource = new InputStreamResource(new FileInputStream(targetFile));

    return ResponseEntity.ok()
            .contentType(MediaType.APPLICATION_OCTET_STREAM)
            .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + targetFile.getName() + "\"")
            .contentLength(targetFile.length())
            .body(resource);
}
  • 扩展说明:如果使用对象存储(如S3、OSS),直接获取对象的输入流即可,无需先下载到本地磁盘,进一步节省服务器存储空间。

额外优化建议

  • 绝对避免在上传/下载流程中使用file.getBytes()这类会将全量文件加载到内存的方法。
  • 超大文件(如10GB+)可考虑分片上传/下载,降低单块数据的内存占用,同时提升传输容错性。
  • 根据服务器硬件配置调整缓冲区大小,平衡内存占用与IO效率。

内容的提问来源于stack exchange,提问作者Márcio

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.27 17:10:03