在上篇《深入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. mysql优化一 之 优化内容概述及开启慢查日志的相关配置

    1-1数据库优化的目的 首先是为了避免出现页面访问错误(基本有三种) (1)由于数据库连接timeout产生的页面5XX错误 (2)由于慢查询造成页面无法加载 (3)由于阻塞造成的数据无法提交 其次: ...

  2. PetGenie

    大概六.七年前当我还在学 Asphyre 的时候,有看过一个以之编写的类似对对碰的“宠物对对碰”小游戏,虽然很简单,但我当时还是小小的沉溺过数个小时.而不久前,在闲逛论坛时无意看到了个以 FireMo ...

  3. easyUI的Dialog和Windows框的应用

    <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/ ...

  4. RMQ

    1.概念: RMQ(Range Minimum/Maximum Query),即区间最值查询,是指这样一个问题:对于长度为n的数列A,回答若干询问RMQ(A,i,j)(i,j<=n),返回数列A ...

  5. 学习git与github的二三事 (一)

    前一段时间看到了一个参加机器人比赛的同学写的经验之谈,他提到了在比赛时,希望同学们学习一下git来管理代码,于是我就某度了一下,发现了廖雪峰老师的网站,受益匪浅,持续学习中,拜谢大神,顺便记录一下自己 ...

  6. Oracle(控制用户权限)

    权限允许用户访问属于其它用户的对象或执行程序, ORACLE系统提供权限:Object 对象级.System 系统级 查看权限的数据字典: 字典名 含义 ROLE_SYS_PRIVS System p ...

  7. FAQ

    1.Baudrare and the speed of Byte. 2. Linux FS and Flash store. 3. SW's Coupling. 4. Protocol and Pro ...

  8. Fair Scheduler 队列设置经验总结

    Fair Scheduler 队列设置经验总结 由于公司的hadoop集群的计算资源不是很充足,需要开启yarn资源队列的资源抢占.在使用过程中,才明白资源抢占的一些特点.在这里总结一下. 只有一个队 ...

  9. HttpClient 4.5.x 工具类设计与实现

    最近,业务需要在java服务端发起http请求,需要实现"GET","POST","PUT"等基本方法.于是想以 "HttpCli ...

  10. CentOs6.5下安装svn

    1.检查是否已安装 rpm -qa subversion 1.1如果需要卸载旧版本(如果想在一台机器安装不同svn,切记不要执行此步骤!!!) yum remove subversion 2.安装 y ...