preparation

本节摘要:本节主要介绍上传文件到指定目录。

引入:

文件上传是开发中常用的功能,本节主要介绍用commons-fileupload-1.1.jar包实现基本的文件上传功能,即上传文件到指定的目录中,同时介绍上传过程中使用到的相关类及其方法。

下载插件:

准备需要的jar包

* commons-fileupload-1.1.jar 文件上传jar包(必须导入)
* commons-io-1.2.jar (必须导入)如果不导入的程序编译时不会报错,但是发布后运行时会报错
* log4j-1.2.8.jar 强烈建议导入,但在本类中不是必须的,后面的上传文件到数据库中的类中会使用
* classes12.jar 连接oracle数据库的jar包,后面的上传文件到数据库中时必须导入

开发环境:

System:xp    JDK:1.5(开发的JDK版本)  Tomcat:5.X  Myeclipse:6.5

注意:编译的JDK版本用JDK1.4(如果用JDK1.5编译,会报”Unsupported major.minor version 49.0”错误)

项目环境:

java 移动文件到新目录 java上传文件到指定目录_上传

文件上传目录介绍:

在D盘根目录新建一个test文件夹,然后在test文件夹中新建以下两个文件夹
* temp:存放超过设置大小的文件(>2M的文件)
* uploadfile:上传文件的存放目录(<=2M的文件)

class&method:

 *DiskFileItemFactory
 * 实现了FileItemFactory接口
 * 主要方法有:
 * public FileItem createItem(String fieldName, String contentType, boolean isFormField, String fileName)
 * setRepository(File repository);设置缓存路径 也有相应的get方法
 * setSizeThreshold(int sizeThreshold);设置上传文件内存缓冲区的大小 也有相应的get方法
 *
 * ServletFileUpload
 * 从FileUpload继承,而FileUpload又从FileUploadBase继承
 * ServletFileUpload(FileItemFactory fileItemFactory);传入一个fileItemFactory对象,构造ServletFileUpload对象
 * List parseRequest(HttpServletRequest request);从request中获得文件请求列表
 * void setSizeMax(long sizeMax);//设置允许上传文件大小 也有相应的get方法
 * setHeaderEncoding(String encoding);//设置上传文件名编码的格式 也有相应的get方法
 *
 * Pattern
 * 正则表达式的编译表示形式,指定为字符串的正则表达式必须首先被编译为此类的实例。
 * 然后,可将得到的模式用于创建 Matcher 对象,依照正则表达式,该对象可以与任意字符序列匹配
 * static Pattern compile(String regex);将给定的正则表达式编译到模式中
 * Matcher matcher(CharSequence input);创建匹配给定输入与此模式的匹配器,返回此模式的新匹配器
 *
 * FileItem
 * 抽象接口,继承Serializable
 * boolean isFormField();判断FileItem类对象封装的数据是否属于一个普通表单字段,
 *                      还是属于一个文件表单字段,如果是普通表单字段则返回true,否则返回false
 * String getName();用于获得文件上传字段中的文件名
 * String getFieldName();用于返回表单字段元素的name属性值
 * long getSize();获得上传文件的大小 单位:字节
 * getContentType();用于获得上传文件的类型
 * void write(File paramFile);用于将FileItem对象中保存的主体内容保存到某个指定的文件中
 *
 * Matcher
 * 通过解释 Pattern 对 character sequence 执行匹配操作的引擎。
 * 通过调用模式的 matcher 方法从模式创建匹配器。创建匹配器后,可以使用它执行三种不同的匹配操作:
 * matches方法尝试将整个输入序列与该模式匹配。
 * lookingAt 尝试将输入序列从头开始与该模式匹配。
 * find 方法扫描输入序列以查找与该模式匹配的下一个子序列。
 * String group(int group)返回在以前匹配操作期间由给定组捕获的输入子序列
 *
 * String
 *  boolean endsWith(String suffix)测试此字符串是否以指定的后缀结束。

start

1.新建web项目UpDown,导入上面介绍的4个jar包

2.新建upload.html文件,用于上传的前台的UI界面




java 移动文件到新目录 java上传文件到指定目录_java_02

java 移动文件到新目录 java上传文件到指定目录_web.xml_03

upload.html


1 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
 2 <html>
 3     <head>
 4         <title>文件上传</title>
 5         <meta name="Generator" content="EditPlus">
 6         <meta name="Author" content="">
 7         <meta name="Keywords" content="">
 8         <meta name="Description" content="">
 9         <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />        
10     </head>
11 
12     <body>
13         <h1>
14             文件上传演示demo---上传到本机文件夹中(程序和上传目录在同一主机)
15         </h1>
16         <!-- 
17         1.上传的内容有图片的时候,form中必须加入 ENCTYPE="multipart/form-data" 
18         2.在<input>标签中必须有name属性(除了提交按钮submit),否则运行时虽然不会报错,但是文件无法成功上传
19 -->
20         <form name="uploadform" method="POST" action="upload"
21             ENCTYPE="multipart/form-data">
22             <table border="1" width="450" cellpadding="4" cellspacing="2"
23                 bordercolor="#9BD7FF">
24                 <tr>
25                     <td width="100%" colspan="2">
26                         文件1:
27                         <input name="a" size="40" type="file">
28                     </td>
29                 </tr>
30                 <tr>
31                     <td width="100%" colspan="2">
32                         文件2:
33                         <input name=b” " size="40" type="file">
34                     </td>
35                 </tr>
36                 <tr>
37                     <td width="100%" colspan="2">
38                         文件3:
39                         <input name="c" size="40" type="file">
40                     </td>
41                 </tr>
42 
43             </table>
44             <br />
45             <br />
46             <table>
47                 <tr>
48                     <td align="center">
49                         <input name="upload" type="submit" value="开始上传" />
50                     </td>
51                 </tr>
52             </table>
53         </form>
54     </body>
55 </html>



 

3.新建servlet文件Upload.java文件,用于对上传的文件进行处理




java 移动文件到新目录 java上传文件到指定目录_java_02

java 移动文件到新目录 java上传文件到指定目录_web.xml_03

upload.java


1 package upload;
  2 
  3 import java.io.File;
  4 import java.io.IOException;
  5 import java.io.PrintWriter;
  6 import java.util.Iterator;
  7 import java.util.List;
  8 import java.util.regex.Matcher;
  9 import java.util.regex.Pattern;
 10 import javax.servlet.ServletException;
 11 import javax.servlet.http.HttpServlet;
 12 import javax.servlet.http.HttpServletRequest;
 13 import javax.servlet.http.HttpServletResponse;
 14 import org.apache.commons.fileupload.FileItem;
 15 import org.apache.commons.fileupload.FileUploadException;
 16 import org.apache.commons.fileupload.disk.DiskFileItemFactory;
 17 import org.apache.commons.fileupload.servlet.ServletFileUpload;
 18 
 19 /**此程序是上传文件到指定的目录的一个小小的demo
 20  * 有以下两个要求:(1)上传的文件不能超过文件指定的最大值(2)对有些后缀名的文件不能上传
 21 */
 22 /**
 23  *Module:       Upload.java
 24  *Description:  上传文件到指定的目录(程序和上传的目录在同一台主机)
 25  *Company:      XXX
 26  *Author:       ptp
 27  *Date:         Feb 6, 2012
 28  */
 29 public class Upload extends HttpServlet {
 30 
 31     // 定义常量,保存文件路径
 32     private static final String FILE_PATH = "D:" + File.separator + "test"
 33             + File.separator + "upload" + File.separator;// 文件上传的路径
 34 
 35     private static final String FILE_TEMP = "D:" + File.separator + "test"
 36             + File.separator + "temp" + File.separator;;// 文件缓存路径
 37 
 38     public void doPost(HttpServletRequest request, HttpServletResponse response)
 39             throws ServletException, IOException {
 40         
 41         response.setContentType("text/html; charset=GB2312");
 42         
 43         PrintWriter out = response.getWriter();
 44     
 45         // ServletFileUpload.isMultipartContent(request);
 46 // 可以处理之前用上面的方法检测request中是否有multipart内容,不过,已经是废弃的方法了
 47 
 48 // 生成DiskFileItemFactory工厂
 49         DiskFileItemFactory factory = new DiskFileItemFactory();
 50         
 51         // 对工厂进行相关的配置
 52 // 设置最多只允许在内存中存储的数据,单位:字节
 53         factory.setSizeThreshold(2048);
 54         
 55         // 设置一旦文件大小超过getSizeThreshold()的值时数据存放在硬盘的目录 文件缓存路径 【暂时没有实现这个功能】
 56 //判断指定的目录是否存在,如果不存在则新建该目录,注意mkdirs()和mkdir()的区别:
 57 //如果test不存在,用mkdir()程序会在后面会报错,用mkdirs()就不会报错
 58         File fileTemp = new File(FILE_TEMP);
 59         if (!fileTemp.exists()){
 60             fileTemp.mkdirs();
 61         }
 62         File filePath1 = new File(FILE_PATH);
 63         if (!filePath1.exists()) {
 64             filePath1.mkdir();//此处可以用mkdir()方法,因为前面的代码执行后test目录一定存在
 65         }
 66         
 67         //设置缓存路径
 68         factory.setRepository(fileTemp);
 69 
 70         // 将DiskFileItemFactory对象传给ServletFileUpload构造方法,生成上传类ServletFileUpload的对象
 71         ServletFileUpload sevletFileUpload = new ServletFileUpload(factory);
 72 
 73         // 设置允许用户上传文件大小,单位:字节,这里设为2M
 74         sevletFileUpload.setSizeMax(2 * 1024 * 1024);
 75         
 76         // 设置编码,解决上传文件名乱码
 77         sevletFileUpload.setHeaderEncoding("GB2312");/**按照JDK的介绍,此方法是解决上传文件名中文乱码问题,但是后面测试发现不能实现*/
 78     
 79         //获得允许用户上传文件大小
 80         long maxSize = sevletFileUpload.getSizeMax();
 81 
 82         try {
 83             /**
 84              * 开始读取上传信息 从request中取到上传文件列表 
 85              * 超过了设置的最大值2M会报异常
 86              * 文件缓存目录不存在也会报异常(前面已经对目录存在做了判断,所以不可能出现目录不存在报的情况)
 87 */
 88             List fileItems = sevletFileUpload.parseRequest(request);
 89             //调用上传文件的方法
 90             if (null != fileItems)
 91                 upLoadFile(fileItems, out);
 92             
 93         } catch (FileUploadException e) {
 94             out.println("对不起,您上传的文件大小超过了允许的最大值" + maxSize / 1024 / 1024 + "M!");
 95             e.printStackTrace();
 96         }
 97     }
 98     
 99     /**
100      * 上传文件
101      * @param fileItems
102      * @param out
103 */
104     public void upLoadFile(List fileItems,PrintWriter out){
105         try{
106         // 依次处理每个上传的文件
107         Iterator iter = fileItems.iterator();
108 
109         // 正则匹配,过滤路径取文件名
110         /*
111          * $ 行的结尾 . 任何字符(与行结束符可能匹配也可能不匹配) + 一次或多次
112          * \\\\匹配FILE_PATH中的\\,4个右斜杠转义后变为2个
113 */
114         String regExp = ".+\\\\(.+)$";
115         
116         // 过滤掉的文件类型
117         String[] errorType = { ".exe", ".com", ".cgi", ".asp" };
118         
119         StringBuffer error=new StringBuffer();
120         
121         //拼接不能上传的文件类型,即字符串error,用于后面显示
122         for(int i=0;i<errorType.length;i++){
123             if (i == errorType.length - 1) {
124                     error.append(errorType[i] + "。");
125             } else {
126                     error.append(errorType[i] + ",");
127             }
128         }
129         
130         Pattern p = Pattern.compile(regExp);//将给定的正则表达式regExp编译到模式中
131         while (iter.hasNext()) {
132             FileItem item = (FileItem) iter.next();
133             /*忽略其他不是文件域的所有表单信息
134             *isFormField()方法判断FileItem类对象封装的数据是否属于一个普通表单字段,
135             *还是属于一个文件表单字段,如果是普通表单字段则返回true,否则返回false
136             *只有是文件表单字段才能进入if中的代码
137 */
138             if (!item.isFormField()) {
139                     String name = item.getName();// 用于获得上传文件的名称,如:c:\documents and settings\administrator\桌面\test.txt
140                     long size = item.getSize();// 获得上传文件的大小
141                     if ((name == null || name.equals("")) && size == 0)// 文件表单为空或文件大小为0跳过本次循环,继续下一次循环
142                         continue;
143                     Matcher m = p.matcher(name);// 创建匹配给定输入与此模式的匹配器
144                     boolean result = m.find();// 方法扫描输入序列以查找与该模式匹配的下一个子序列
145                     if (result) {
146                         for (int temp = 0; temp < errorType.length; temp++) {
147                             if (m.group(1).endsWith(errorType[temp])) {
148                                 throw new IOException("非法文件类型禁止上传,以下文件类型不能上传:"+error);
149                             }
150                         }
151                         try {
152 
153                             //保存上传的文件到指定的目录
154                             File filePath=new File(FILE_PATH + m.group(1));
155                             item.write(filePath);
156 
157                             //在页面上输出上传文件后的信息
158                             out.print(name + "  " + size + "<br>");
159                             
160                         } catch (Exception e) {
161                             out.println(e);
162                         }
163                     } else {
164                         throw new IOException("上传文件失败");
165                     }
166                 }
167             }
168         } catch (IOException e) {
169             out.println(e);
170         }
171     }
172 
173     public void doGet(HttpServletRequest request, HttpServletResponse response)
174             throws ServletException, IOException {
175         this.doPost(request, response);
176     }
177 }



 

4.配置web.xml文件




java 移动文件到新目录 java上传文件到指定目录_java_02

java 移动文件到新目录 java上传文件到指定目录_web.xml_03

web.xml


1 <?xml version="1.0" encoding="UTF-8"?>
 2 <web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"
 3     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 4     xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 
 5     http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
 6 
 7     <servlet>
 8         <servlet-name>upload</servlet-name>
 9         <servlet-class>upload.Upload</servlet-class>
10     </servlet>
11     <servlet-mapping>
12         <servlet-name>upload</servlet-name>
13         <url-pattern>/upload</url-pattern>
14     </servlet-mapping>
15 
16 </web-app>



 

5.发布项目

result

访问的URL如下:

http://localhost:8080/UpDown/upload.html

upload.html页面如下:

java 移动文件到新目录 java上传文件到指定目录_数据库_08

上传完成后跳转显示的页面如下:

java 移动文件到新目录 java上传文件到指定目录_java 移动文件到新目录_09

检查指定的上传目录:

java 移动文件到新目录 java上传文件到指定目录_java 移动文件到新目录_10

检查文件大小限制(上传一个大于2M的文件,然后点击”开始上传”,界面显示如下):

java 移动文件到新目录 java上传文件到指定目录_数据库_11

检查文件后缀名过滤(上传一个exe文件,然后点击”开始上传”,界面显示如下):

java 移动文件到新目录 java上传文件到指定目录_web.xml_12

遗留&拓展部分:

 * 1.中文乱码问题  IE界面显示乱码、上传目录乱码
 * 2.上传目录和程序不在同一台主机上的处理方式  
 * 2.文件缓存问题
 * 3.文件的端点续传功能
 * 4.上传滚动条问题

answer

1.关于中文乱码问题的解决方法

经过测试以下语句设置为utf-8即可解决,设置为gbk或gb2312都无法解决中文乱码问题

sevletFileUpload.setHeaderEncoding("utf-8");