I'm wondering if there a real difference when a Sprin MVC controller method returns byte array byte[]
to represent a downloaded file or when I copy InputStream
object to the ServletOutputStream
object?
The reason I'm asking is that I have to make sure that there won't be any OutOfMemory errors when downloading large files. Will the passing file through the ServletOutputStream
help to avoid it?
Passing byte array:
byte[] download() {
return getUrlContentAsByteArray();
}
Passing in the ServletOutputStream:
void download(HttpServletResponse response) {
InputStream content = getUrlContentAsStream();
ServletOutputStream outputStream = response.getOutputStream();
response.reset();response.setContentType(ContentType.APPLICATION_OCTET_STREAM.getMimeType());
IOUtils.copyLarge(inputStream, outputStream);
}
In your first example, you have to read the entire response into memory and store it in a byte array. That will require at least as much memory as the size of the response.
In your second example, you do not keep the entire response in memory at once, but use IOUtils.copy
to copy the content in multiple, small chunks from the source and into the servlet response. IOUtils is by default using a 4kB large buffer. You are however using a strange mix of both Spring and Servlet APIs.
Using Spring MVC alone, you can leave out the servlet API, return the InputStream wrapped as a Resource and let Spring do the copy job for you:
@RequestMapping(value = "/download", method = RequestMethod.GET)
@ResponseBody
public ResponseEntity<Resource> download() {
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
InputStream is = null; // get your input stream here
Resource resource = new InputStreamResource(is);
return new ResponseEntity<>(resource, headers, HttpStatus.OK);
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With