文件的上传和下载—上传的实现,注意事项

 实现WEB开发中的文件上传功能,需完成如下二步操作:

在WEB页面中添加上传输入项,<input type=“life” name=“”>,使用时注意:

1. 必须要设置input输入项的name属性,否则浏览器将不会发送上传文件的数据。

2. 必须把input项的enctype属值设为multipart/form-data.设置该值后,浏览器在上传文件时,将把文件数据附带在http请求消息体中,并使用MIME协议对上传的文件进行描述,以方便接收方对上传数据进行解析和处理。

如何在Servlet中读取文件上传数据,并保存到服务器本地硬盘中?

Request对象提供了一个getInputStream()方法,使用这个方法可以获取浏览器提交过来的输入流。但如果浏览器上传多个文件时,我们应该如何区分开来?这是一项复杂的工作。

为了方便用户处理文件上传数据,Apache开源组织提供了用于处理上面应用的开源组件——Commons-fileupload。这个组件使用简单,性能也比较优异,所以几乎都使用它来实现上传文件的处理功能。

DiskFileItemFactory是创建FileItem对象的工厂,这个工厂常用方法:

1. public DiskFileItemFactory(int sizeThreshold, java.io.File repository),常用的构造函数。

2. public void setSizeThreshold(int sizeThreshold),设置内存缓冲区的大小,默认值为10K。当上传文件大于缓冲区大小时, fileupload组件将使用临时文件缓存上传文件。

3. public void setRepository(java.io.File repository),指定临时文件目录,默认值为System.getProperty("java.io.tmpdir")。

 

ServletFileUpload 负责处理上传的文件数据,并将表单中每个输入项封装到一个FileItem对象中。常用方法有:

1. boolean isMultipartContent(HttpServletRequest request),判断上传表单是否为上传表单类型。

2. List parseRequest(HttpServletRequest request),解析request对象,并把表单中的每一个输入项包装到一个fileItem 对象中,并返回一个保存了所有FileItem的list集合。

3. setFileSizeMax(long fileSizeMax),设置上传文件的最大尺寸值。

4. setSizeMax(long sizeMax),设置上传文件总量的最大值。

5. setHeaderEncoding(java.lang.String encoding),设置编码格式。如果文件路径中存在中文可能会造成文件路径乱码,用此方法处理可以解决。

 

上传文件案例:

  1. public class FileuploadServlet extends HttpServlet {   
  2.   
  3.   
  4.   
  5. public void dopost(HttpServletRequest request, HttpServletResponse response)   
  6.   
  7. throws ServletException, IOException {   
  8.   
  9. // 创建文件处理工厂,它用于生成FileItem对象。   
  10.   
  11. DiskFileItemFactory difactory = new DiskFileItemFactory();   
  12.   
  13. //设置缓存大小,如果上传文件超过缓存大小,将使用临时目录做为缓存。   
  14.   
  15. difactory.setSizeThreshold(1024 * 1024);   
  16.   
  17.   
  18.   
  19. // 设置处理工厂缓存的临时目录,此目录下的文件需要手动删除。   
  20.   
  21. String dir = this.getServletContext().getRealPath("/");   
  22.   
  23. File filedir = new File(dir + "filetemp");   
  24.   
  25. if (!filedir.exists())   
  26.   
  27. filedir.mkdir();   
  28.   
  29. difactory.setRepository(filedir);   
  30.   
  31.   
  32.   
  33. // 设置文件实际保存的目录   
  34.   
  35. String userdir = dir + "files";   
  36.   
  37. File fudir = new File(userdir);   
  38.   
  39. if (!fudir.exists())   
  40.   
  41. fudir.mkdir();   
  42.   
  43.   
  44.   
  45. // 创建request的解析器,它会将数据封装到FileItem对象中。   
  46.   
  47. ServletFileUpload sfu = new ServletFileUpload(difactory);   
  48.   
  49. // 解析保存在request中的数据并返回list集合   
  50.   
  51. List list = null;   
  52.   
  53. try {   
  54.   
  55. list = sfu.parseRequest(request);   
  56.   
  57. } catch (FileUploadException e) {   
  58.   
  59. e.printStackTrace();   
  60.   
  61. }   
  62.   
  63.   
  64.   
  65. // 遍历list集合,取出每一个输入项的FileItem对象,并分别获取数据   
  66.   
  67. for (Iterator it = list.iterator(); it.hasNext();) {   
  68.   
  69. FileItem fi = (FileItem) it.next();   
  70.   
  71. if (fi.isFormField()) {   
  72.   
  73. System.out.println(fi.getFieldName());   
  74.   
  75. System.out.println(fi.getString());   
  76.   
  77. } else {   
  78.   
  79. //由于客户端向服务器发送的文件是客户端的全路径,在这我们只需要文件名即可   
  80.   
  81. String fifilename = fi.getName();   
  82.   
  83. int index = filename.lastIndexOf("\\");   
  84.   
  85. if(index != -1)   
  86.   
  87. filenamefilename = filename.substring(index+1);   
  88.   
  89. //向服务器写出文件   
  90.   
  91. InputStream in = fi.getInputStream();   
  92.   
  93. FileOutputStream fos = new FileOutputStream(fudir + "/" +filename);   
  94.   
  95. byte[] buf = new byte[1024];   
  96.   
  97. int len = -1;   
  98.   
  99. while((len = in.read(buf)) != -1){   
  100.   
  101. fos.write(buf, 0, len);   
  102.   
  103. }   
  104.   
  105. // 关闭流   
  106.   
  107. if(in != null){   
  108.   
  109. try{   
  110.   
  111. in.close();   
  112.   
  113. }finally{   
  114.   
  115. if(fos!=null)   
  116.   
  117. fos.close();   
  118.   
  119. }   
  120.   
  121. }   
  122.   
  123. }   
  124.   
  125. }   
  126.   
  127. }   
  128.   
  129.   
  130.   
  131. public void doGet(HttpServletRequest request, HttpServletResponse response)   
  132.   
  133. throws ServletException, IOException {   
  134.   
  135. doPost(request, response);   
  136.   
  137. }   
  138.   
  139. }   



 

 

上传文件的处理细节(1):

1. 中文文件乱码的问题,可以调用两个方法来设置字符编码:servletUpLoader.setHeaderEncoding()或request.setCharacterEncoding()。我们可以在源文件的创建ServletFileUpload对象后边添加如下代码:

sfu.setHeaderEncoding("UTF-8");



2. 临时文件的删除,如果临时文件大于setSizeThreshold设置的缓存大小,Commons-fileupload组件将使用setRepository设置的临时目录来保存上传的文件,上传完成后我们需要手动调用FileItem.delete来删除临时文件。建议不要修改缓存区大小,如果设置缓存为1MB,1000个用户上传文件就需要1000MB内存,服务器会受不了的。我们删除掉setSizeThreshold的代码,并在每次完成一个文件后添加下而的代码:

// 删除临时目录中的文件

fi.delete();



上传文件的处理细节(2):

1. 在上面的代码中,我们将文件的实际保存目录设置在WEB-INF目录之外。这样外部可以直接访问被上传的文件,这会造成安全问题。比如用户上传了一个带有恶意脚本功能的JSP文件,然后从外部访问执行了JSP文件…后果不堪设想。所以我们将源代码中对应位置处修改如下:

// 之所以放在"WEB-INF"目录下是为了防止上传的文件被直接被访问的安全问题

String userdir = dir + "WEB-INF/files";



2. 一个WEB应用会许多不同的用户访问,不同的用户可能会上传相同名称的文件,如果这样可能会造成文件覆盖的情况发生,所以我们必须保证文件名称的唯一性,我编写一个方法来生成唯一性名称的文件名:

/**

* 生成具有唯一性的UUID文件名称

* @param fileName

* @return

*/

private String uuidName(String fileName){

UUID uuid = UUID.randomUUID();

return uuid.toString() + "_" + fileName;

}

我们将代码“filename = filename.substring(index + 1);”修改为:filename = uuidName(filename.substring(index + 1));

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值