在上篇《深入springMVC------文件上传源码解析(上篇) 》中,介绍了springmvc文件上传相关。那么本篇呢,将进一步介绍springmvc 上传文件的效率问题。

相信大部分人在处理文件上传逻辑的时候会直接获取输入流直接进行操作,伪代码类似这样:

@RequestMapping(value = "/upload", method = RequestMethod.POST)
public ResultView upload(@RequestParam("file") MultipartFile file) {
Inputstream in = file.getInputStream();
...

但是,出于效率,其实我个人更推荐使用 MultipartFile 的 transferTo 方法进行操作,类似这样:

@RequestMapping(value = "/upload", method = RequestMethod.POST)
public ResultView upload(@RequestParam("file") MultipartFile file) {
file.transferTo(new File(destFile));
...

为什么呢?这个就得从源码说起,废话不多说,咱们直接去看源码吧:

1. 先看 MultipartFile(其实现类CommonsMultipartFile) 的getInputStream方法:

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]));
}

通过源码可以看到,spring是通过commons-fileupload 中的FileItem对象去获取输入流,那么就去看看FileItem(其实现类DiskFileItem)的对应方法:

DiskFileItem:

public InputStream getInputStream()
throws IOException {
if (!isInMemory()) {
return new FileInputStream(dfos.getFile());
} if (cachedContent == null) {
cachedContent = dfos.getData();
}
return new ByteArrayInputStream(cachedContent);
}

通过源码可以看到:先去查看是否存在于内存中,如果存在,就将内存中的file对象包装为文件流, 如果不存在,那么就去看缓存,如果缓存存在就从缓存中获取字节数组并包装为输入流。

接下来,咱们再看看 CommonsMultipartFile 的 transferTo 方法,以便形成比较:

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());
}
}

不多说,主要看 this.fileItem.write(dest) 这一句,利用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();
........

通过源码可以看到 transfoTo 方法很干净利落,直接去将内存中的文件通过输出流写出到指定的file 。 等等,跟上面的 getInputStream方法相比,是不是省了点步骤? 是的,再来一张图,清晰地表示两个方法地不同之处:

图中:

红色线表示使用的是transferTo方法,黑色线代表getInputStream方法, 可见,transferTo直接将内存中的文件缓存直接写入到磁盘的物理文件, 而getInputStream方法会中转一次(先通过getInputStream从内存中获取流,再通过outputStream输出到磁盘物理文件)。两者相比,即使从步骤来看,你也能看出来transferTo效率更高了吧。

好啦,本篇就到此结束啦!

深入springMVC源码------文件上传源码解析(下篇)的更多相关文章

  1. 使用SpringMVC框架实现文件上传和下载功能

    使用SpringMVC框架实现文件上传和下载功能 (一)单个文件上传 ①配置文件上传解释器 <!—配置文件上传解释器 --> <mvc:annotation-driven>&l ...

  2. (转)SpringMVC学习(九)——SpringMVC中实现文件上传

    http://blog.csdn.net/yerenyuan_pku/article/details/72511975 这一篇博文主要来总结下SpringMVC中实现文件上传的步骤.但这里我只讲单个文 ...

  3. SpringMVC+BUI实现文件上传(附详解,源码下载)

    中午有限时间写这博文,前言就不必多说了,直奔主题吧. BUI是一个前端框架,关于BUI的介绍请看博主的文章那些年用过的一些前端框架. 下面我们开始实例的讲解! 一.效果演示: 上传成功后,会发现本地相 ...

  4. ajaxFileUpload 实现多文件上传(源码)

    按照原ajaxFileUpload.js是不能多文件上传的.需要对源码进行修改:主要修改了fileElementId部分 具体参考 https://blog.csdn.net/itmyhome1990 ...

  5. SpringMVC国际化与文件上传

    点击阅读上一章 其实SpringMVC中的页面国际化与上一章的验证国际化基本一致. 1.对页面进行国际化 1)首先我们对Spring配置文件中添加国际化bean配置 <!-- 注册国际化信息,必 ...

  6. SpringMvc commons-fileupload图片/文件上传

    简介 SpringMvc文件上传的实现,是由commons-fileupload这个jar包实现的. 需求 在修改商品页面,添加上传商品图片功能. Maven依赖包 pom.xml <!-- 文 ...

  7. SpringMVC框架06——文件上传与下载

    1.文件上传 Spring MVC框架的文件上传是基于commons-fileupload组件的文件上传,只不过Spring MVC框架在原有文件上传组件上做了进一步封装,简化了文件上传的代码实现. ...

  8. springMVC实现多文件上传

    <h2>上传多个文件 实例</h2> <form action="/workreport/uploadMultiFile.html" method=& ...

  9. SpringMvc入门五----文件上传

      知识点: SpringMvc单文件上传 SpringMvc多文件上传   这里我直接演示多文件上传,单文件的上传就不说了,不过代码都是现成的. 效果预览:   DEMO图:     添加文件上传j ...

随机推荐

  1. maven项目和普通项目转换

     

  2. Nginx的安装配置

    1.安装PCRE库 $ cd /usr/local/ $ https://sourceforge.net/projects/pcre/files/pcre/8.36/ $ tar -zxvf pcre ...

  3. 2D空间中判断一点是否在三角形内

    要注意如果是XY坐标轴的2D空间,要取差乘分量z而不是y. 实现原理是,将三角形ABC三个边(AB,BC,CA)分别与比较点判断差乘,如果这3个差乘结果表示的方向一致,说明就在三角形内. 效果: 代码 ...

  4. 封装好的AFN网络请求框架和MBProgress

    demo:https://github.com/IMCCP/CCPAFNNetworking(收藏下来)

  5. django之分页、cookie装饰器

    一.分页代码如下 from django.utils.safestring import mark_safe class Page: def __init__(self, current_page, ...

  6. 描述性统计分析-用脚本将统计量函数批量化&分步骤逐一写出

    计算各种描述性统计量函数脚本(myDescriptStat.R)如下: myDescriptStat <- function(x){ n <- length(x) #样本数据个数 m &l ...

  7. R语言基本操作函数---变量的基本操作

    1.变量变换        as.array(x),as.data.frame(x),as.numeric(x),as.logical(x),as.complex(x),as.character(x) ...

  8. grep命令

    grep (缩写来自Globally search a Regular Expression and Print)是一种强大的文本搜索工具,它能使用正则表达式搜索文本,并把匹配的行打印出来. grep ...

  9. html5本地存储(localStorage)使用介绍

    1.html5几种存储形式 本地存储(localStorage && sessionStorage) 离线缓存(application cache) indexedDB 和 webSQ ...

  10. PHP 编译安装

    1, 获取源码wget -O php.tar.gz http://am1.php.net/get/php-5.6.27.tar.gz/from/this/mirrortar zxvf php.tar. ...