Go deep into springMVC source code ------ file upload source code parsing (next), springmvc ------
In the previous article "go deep into springMVC ------ file upload source code parsing (previous article)", I introduced springmvc file upload. In this article, we will further introduce springmvc's file upload efficiency.
I believe that most people directly obtain the input stream for operations when processing the File Upload logic. The pseudo code is similar to this:
@RequestMapping(value = "/upload", method = RequestMethod.POST)public ResultView upload(@RequestParam("file") MultipartFile file) { Inputstream in = file.getInputStream(); ... }
However, for efficiency, I personally recommend using the transferTo method of MultipartFile for operations, such:
@RequestMapping(value = "/upload", method = RequestMethod.POST)public ResultView upload(@RequestParam("file") MultipartFile file) { file.transferTo(new File(destFile)); ... }
Why? Let's start with the source code. Let's look at the source code:
1. First read the getInputStream method of MultipartFile (its implementation class CommonsMultipartFile:
CommonsMultipartFile:
public InputStream getInputStream() throws IOException { if (!isAvailable()) { throw new IllegalStateException("File has been moved - cannot be read again"); } InputStream inputStream = this.fileItem.getInputStream(); return (inputStream != null ? inputStream : new ByteArrayInputStream(new byte[0])); }
From the source code, we can see that spring obtains the input stream through the FileItem object in commons-fileupload, so let's look at the corresponding methods of FileItem (its implementation class DiskFileItem:
DiskFileItem:
public InputStream getInputStream() throws IOException { if (!isInMemory()) { return new FileInputStream(dfos.getFile()); } if (cachedContent == null) { cachedContent = dfos.getData(); } return new ByteArrayInputStream(cachedContent); }
You can see from the source code: first check whether the object exists in the memory. If yes, wrap the file object in the memory as a file stream. If not, check the cache, if the cache exists, obtain the byte array from the cache and encapsulate it as an input stream.
Next, let's take a look at the transferTo method of CommonsMultipartFile to form a comparison:
CommonsMultipartFile:
@Override public void transferTo(File dest) throws IOException, IllegalStateException { if (!isAvailable()) { throw new IllegalStateException("File has already been moved - cannot be transferred again"); } if (dest.exists() && !dest.delete()) { throw new IOException( "Destination file [" + dest.getAbsolutePath() + "] already exists and could not be deleted"); } try { this.fileItem.write(dest); if (logger.isDebugEnabled()) { String action = "transferred"; if (!this.fileItem.isInMemory()) { action = isAvailable() ? "copied" : "moved"; } logger.debug("Multipart file '" + getName() + "' with original filename [" + getOriginalFilename() + "], stored " + getStorageDescription() + ": " + action + " to [" + dest.getAbsolutePath() + "]"); } } catch (FileUploadException ex) { throw new IllegalStateException(ex.getMessage()); } catch (IOException ex) { throw ex; } catch (Exception ex) { logger.error("Could not transfer to file", ex); throw new IOException("Could not transfer to file: " + ex.getMessage()); } }
Not to mention, we mainly look at this. fileItem. write (dest) and use the related methods in commons-fileupload:
DiskFileItem:
public void write(File file) throws Exception { if (isInMemory()) { FileOutputStream fout = null; try { fout = new FileOutputStream(file); fout.write(get()); } finally { if (fout != null) { fout.close(); } } } else { File outputFile = getStoreLocation(); if (outputFile != null) { // Save the length of the file size = outputFile.length();........
From the source code, we can see that the transfoTo method is very neat, and directly writes files in the memory to the specified file through the output stream. Wait. Compared with the above getInputStream method, does it save some steps? Yes, let's look at another image to clearly show the differences between the two methods:
Figure:
The red line indicates that the transferTo method is used, and the black line indicates the getInputStream method. It can be seen that transferTo directly writes the files in the memory cache to the physical files on the disk, the getInputStream method will be used once (the stream is obtained from the memory through getInputStream and then output to the disk physical file through outputStream ). Compared with the two, you can see that transferTo is more efficient even from the perspective of steps.
Well, this article is over!