文件的上传
博客专区 > _-Leon-_ 的博客 > 博客详情
文件的上传
_-Leon-_ 发表于3年前
文件的上传
  • 发表于 3年前
  • 阅读 197
  • 收藏 8
  • 点赞 0
  • 评论 0

腾讯云 新注册用户 域名抢购1元起>>>   

摘要: 文件的上传

#文件上传 文件的上传其实是比较简单的,只要实现两步就可以了:

  • 在web页面中添加上传输入项
  • 在servlet中读取上传文件的数据,并保存到本地磁盘中

###添加上传输入项也需要两步

  • 使用 <input type="file">标签,一定要设置name属性,不然不会被提交
  • 将所在form的 enctype 属性设置为 multipart/form-data,设置该值后,浏览器就会把上传的文件数据附带在http请求的消息体中,并使用MIME协议对上传文件进行描述

###在Servlet中获取数据

如果提交的表单使用了 multipart/form-data,那么就Servlet中就不能直接用requets对象来获取数据了,因为如果使用了 multipart/form-data 设置表单,浏览器就会使用MIME协议来描述表单的所有项。那么如果要获取数据,就需要使用request对象来获取输入流,然后对流进行MIME解析。对MIME解析不是一件容易的事情,因为上传的文件类型会非常多,而个数不定。所以一般在实际开发中,一般使用第三方上传组件来完成文件上传功能。

>第三方上传组件比较多,比较常用的有:Commons-fileupload、Cos组件等

###Commons-fileupload Commons-fileupload是Apache基金会的一个开源组件,该组件性能优异,并且API使用也比较简单。如果要使用该组件,需要给应用添加两个Jar包:

  • Commons-fileupload
  • Commons-io(Commons-fileupload组件从1.1版本开始,依赖该Jar)

###Commons-fileupload组件工作图: Commons-fileupload组件工作图

根据上图的步骤,可以看出,步骤非常简单:使用DiskFileItemFactory获取一个ServletFileupload对象,然后获取FileItem即可。获取到FileItem之后,也有对应的API来获取FileItem的一些信息:

  • 普通字段:isFormField() getFieldName() getString()
  • 上传文件:getInputStream() getName()

demo示例多个文件上传的处理。(对于ie6的绝对路径的截取来获取文件名)

#上传需要处理的细节 上传其实并不难,主要是需要细心,去处理很多细节,来把程序写得易用。

###乱码问题

  • 上传文件的乱码问题,直接使用ServletFileupload对象的setHeaderEncoding()方法来解决
  • 普通输入项的乱码解决,只能使用手动来转换,使用request设置编码已经没有用了,inputValue = new String(inputValue.getBytes("ISO8859-1"), "UTF-8"),也可以直接使用FileItem的getString方法,这个方法被重载了,也设置编码,其实内部实现代码就是手动转码的代码。

###判断表单类型

  • 在开发中,应该首先判断提交的表单是否 multipart/form-data 类型的表单。使用 ServletFileupload 对象的isMultipartContent()方法来进行判断
  • 如果是普通表单,就应该使用普通方法来进行处理,如果是上传表单,就使用组件处理

###设置缓冲区 在上传中,很有可能有比较大型的文件,那么对于大型文件的上传处理,比较好的处理就是使用缓冲区来进行处理。fileupload组件支持内存缓冲区和临时文件缓冲区。 当文件不是很大的时候,直接使用内存缓冲区来处理,但是如果文件太大,内存缓冲区就不过用了,就要使用临时文件来处理,这个具体的临界值要根据实际的服务器环境来恒定,使用了临时文件后,对应的输入流就是从临时文件来读取数据了。

  • 使用 DiskFileItemFactory 对象来设置缓冲区:
      * `setSizeThreshold(int sizeThreshold)`,设置内存缓冲区的大小,默认值为10K。当上传文件大于缓冲区大小时,将使用临时文件缓存上传文件
      * `setRepository(java.io.File repository)`,指定临时文件目录,默认值为 System.getProperty("java.io.tmpdir")
      * 可以在工厂创建的时候指定这些值
    

有一点要特别注意,如果使用了临时文件存储,临时文件是不会自动删除的,在上传结束后,需要手动删除fileitem.delete()

###上传的安全隐患 一般的,不要将上传文件的保存目录设置在项目根目录中,这是一件很危险的事情。因为别人可以将一个写好的jsp上传上去,然后通过客户端让其运行,如果该jsp中有恶意代码,将会攻陷服务器(shutdown -s -t 200shutdown -a)。 应该将上传文件的目录保存到WEB-INF文件夹中,这个文件夹是禁止非本应用资源访问的。

###上传文件的类型 这个其实很简单,首先定义一个可上传类型的集合或者枚举,然后对上传文件的名字进行验证就可以了。

###上传文件的大小 上传是由解析器来处理的,所以设置上传文件大小的设置在ServletFileupload中,它的常用方法有:

  • bololean isMultipartContent(HttpServletRequest request),判断上传表单是否为 multipart/form-date 类型
  • List parseRequest(HttpServletRequest request),解析request对象,封装成FileItem集合
  • setFileSizeMax(long fileSizeMax) ,设置文件上传最大值
  • setSizeMax(long sizeMax),设置上传文件总量的最大值
  • setHeaderEncoding(java.lang.String encoding),设置编码格式

###多文件上传的空文件 在实际开发中,一般都是对一个文件的处理,多文件并不多,多文件的上传本身就相对要考虑的问题多一些。如果是多文件,而用户没有全部选择文件,这时也是很容易导致后台程序出错的,所以在后台也要做这方面的处理。(非空验证,如果是空,就不要处理等)

###上传文件的名称 在做上传的时候,很可能出现重复的文件名称,那么就需要给每个上传的文件一个唯一的名称。常见的命名策略有:使用UUID+文件名称、使用毫秒数+随机数+文件名称等等。 在这个过程中有一个问题,那就是把所有的文件是否存在一个文件夹中呢?答案肯定是不能。对于操作系统来说,一个文件夹的文件过多,那么在查找的时候必然会影响性能,所以对于上传的文件,不光要考虑文件名称的唯一性,还需要考虑怎样提升查找的性能。 >一般的做法是按照年月日去创建文件夹目录结构,这样就可以很容易的解决掉这个问题。 >还有一些使用算法来实现的,这种情况一般应用在特别多的上传量的情况下(base64计算文件夹,hash值计算文件夹)。

共有 人打赏支持
粉丝 11
博文 17
码字总数 34045
×
_-Leon-_
如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
* 金额(元)
¥1 ¥5 ¥10 ¥20 其他金额
打赏人
留言
* 支付类型
微信扫码支付
打赏金额:
已支付成功
打赏金额: