Master Large File Streaming in Spring Boot 3: Upload & Download Techniques
This article explains how to efficiently handle massive file uploads and downloads in Spring Boot 3 using traditional blocking I/O, reactive WebFlux streams, and proper configuration to keep memory usage low while maintaining high performance.
Introduction
In web applications, uploading and downloading large files is a tricky challenge. Spring Boot simplifies this with built‑in streaming mechanisms such as InputStreamResource and OutputStream, which keep memory consumption low when processing big files.
Large File Upload Streaming
Spring Boot supports multipart file upload by default, but loading an entire large file into memory can cause performance problems. Using a blocking InputStream to read the file in small chunks avoids high memory usage.
@PostMapping("")
public ResponseEntity<String> uploadFile(@RequestParam("file") MultipartFile file) {
Path filePath = Paths.get("d:/upload/" + file.getOriginalFilename());
try (InputStream inputStream = file.getInputStream();
OutputStream outputStream = Files.newOutputStream(filePath, StandardOpenOption.CREATE)) {
byte[] buffer = new byte[8192];
int bytesRead;
while ((bytesRead = inputStream.read(buffer)) != -1) {
outputStream.write(buffer, 0, bytesRead);
}
} catch (IOException e) {
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body("文件上传错误: " + e.getMessage());
}
return ResponseEntity.ok("文件上传成功");
}Reading the file in 8 KB blocks prevents excessive memory consumption, and the try‑with‑resources statement automatically closes streams.
Reactive (WebFlux) Upload
Spring WebFlux provides a non‑blocking way to handle uploads using Flux<DataBuffer>. The file is processed as a continuous data stream, which is ideal for cloud environments or concurrent large‑file uploads.
@PostMapping(value = "/reactive/stream", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
public Mono<Void> uploadLargeFile(@RequestPart("file") Flux<DataBuffer> fileBuffer,
@RequestPart("fileName") String fileName) {
Path path = Paths.get("d:/upload/" + fileName);
return DataBufferUtils.write(fileBuffer, path, StandardOpenOption.CREATE).then();
}If both spring-boot-starter-web and spring-boot-starter-webflux are on the classpath, set the application type to reactive:
spring:
main:
web-application-type: reactiveMultipart size limits can be configured as follows:
spring:
servlet:
multipart:
max-file-size: 100MB
max-request-size: 200MBUpload Summary
Simple upload: MultipartFile works for small files but may not be optimal for large ones.
Memory‑efficient upload: Using InputStream processes files in chunks.
Reactive approach: Flux<DataBuffer> in WebFlux offers the best performance for concurrent large uploads.
Large File Download Streaming
Downloading huge files without loading them entirely into memory can be achieved with InputStreamResource, which streams data to the client in small chunks.
@GetMapping("/stream")
public ResponseEntity<InputStreamResource> downloadFile() throws IOException {
Path filePath = Paths.get("d:/devsoft/Chat2DB-Setup-1.0.11.exe");
InputStreamResource resource = new InputStreamResource(Files.newInputStream(filePath));
return ResponseEntity.ok()
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=Chat2DB-Setup-1.0.11.exe")
.contentType(MediaType.APPLICATION_OCTET_STREAM)
.body(resource);
}The Files.newInputStream method opens a stream without loading the whole file, and the resource supplies data blocks as they become available.
OutputStream Download
Using OutputStream gives finer control over buffer size and transmission speed.
@GetMapping("/os")
public void downloadFileStream(HttpServletResponse response) throws IOException {
Path filePath = Paths.get("d:/devsoft/Chat2DB-Setup-1.0.11.exe");
response.setContentType("application/octet-stream");
response.setHeader("Content-Disposition", "attachment; filename=Chat2DB-Setup-1.0.11.exe");
try (OutputStream out = response.getOutputStream();
InputStream in = Files.newInputStream(filePath)) {
byte[] buffer = new byte[8192];
int bytesRead;
while ((bytesRead = in.read(buffer)) != -1) {
out.write(buffer, 0, bytesRead);
}
}
}Reactive (WebFlux) Download
WebFlux can serve large files non‑blocking by streaming DataBuffer objects.
@GetMapping(value = "/reactive", produces = MediaType.APPLICATION_OCTET_STREAM_VALUE)
public Mono<Void> downloadFileReactive(ServerHttpResponse response) {
Path filePath = Paths.get("d:/devsoft/Chat2DB-Setup-1.0.11.exe");
Flux<DataBuffer> fileStream = DataBufferUtils.read(filePath, new DefaultDataBufferFactory(), 8192);
response.getHeaders().add("Content-Disposition", "attachment; filename=Chat2DB-Setup-1.0.11.exe");
return response.writeWith(fileStream);
}This method uses Flux<DataBuffer> to transmit 8 KB chunks without blocking threads, making it ideal for high‑concurrency scenarios such as media streaming or cloud file storage services.
Download Summary
InputStreamResource: Simple, low‑memory streaming for standard downloads.
OutputStream: Allows custom buffer control for performance‑critical cases.
WebFlux (Flux<DataBuffer>): Best for concurrent large‑file downloads in reactive applications.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Spring Full-Stack Practical Cases
Full-stack Java development with Vue 2/3 front-end suite; hands-on examples and source code analysis for Spring, Spring Boot 2/3, and Spring Cloud.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
