转自:http://blog.csdn.net/yerenyuan_pku/article/details/52540661#t3
由于文件上传需要注意的细节太多了,一篇文章全部容纳这些细节,真是太长了,索性再写一篇文章,紧衔上一篇文章文件上传(二)。
处理文件上传需要注意的细节
如何判断空的上传输入项
在处理完文件上传需要注意的第6个细节后,测试时,如果我们像下面这样上传文件:
点击上传按钮,会抛如下异常:
这时,我们一定要冷静下来,看到异常不要害怕,而是要学会看异常,找出抛异常的原因。根据以上的异常显示,在代码
String ext = fileName.substring(fileName.lastIndexOf("."));
处出现错误,即在获取文件的扩展名时嗝屁了,为什么会这样呢?原因是:我们在第二个上传文件输入项中没有选择一个文件进行上传,那么在UploadServlet的代码中这句代码:
String fileName = item.getName().substring(item.getName().lastIndexOf("\\")+1);
获取到的文件名是""
字符串,即空字符串,而不是null,这样在获取文件的扩展名时,fileName.lastIndexOf(".")
返回的就是-1。fileName.substring(fileName.lastIndexOf("."));
就是从索引为-1的位置截取,所以会报这样的异常:
java.lang.StringIndexOutOfBoundsException: String index out of range: -1
这个时候,我们就要将UploadServlet的代码修改为:
public class UploadServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// List<String> types = Arrays.asList(".jpg",".gif",".avi",".txt");
List<String> types = Arrays.asList("jpg","gif","avi","txt");
// request.setCharacterEncoding("UTF-8");
try {
DiskFileItemFactory factory = new DiskFileItemFactory();
factory.setSizeThreshold(1024*1024);
factory.setRepository(new File(this.getServletContext().getRealPath("/temp")));
ServletFileUpload upload = new ServletFileUpload(factory);
// 限制上传文件的大小
upload.setFileSizeMax(1024*1024*5); // 只要超出5M,for循环在解析的时候就会抛异常
// 提交的表单类型不是multipart/form-data,没必要用解析器进行解析数据,按照传统方式获取表单数据
if (!upload.isMultipartContent(request)) {
// 按照传统方式获取表单数据
request.getParameter("username");
blabla......
return;
}
// 解决上传文件的中文乱码问题,设置解析器的编码,到底设什么编码,也不能瞎写,一定要看表单的数据是以什么编码提交的!
upload.setHeaderEncoding("UTF-8");
List<FileItem> list = upload.parseRequest(request);
for (FileItem item : list) {
if (item.isFormField()) {
// 为普通输入项的数据
String inputName = item.getFieldName();
String inputValue = item.getString("UTF-8");
// inputValue = new String(inputValue.getBytes("ISO8859-1"), "UTF-8");
System.out.println(inputName + "=" + inputValue);
} else {
// 代表当前处理的item里面封装的是上传文件
String fileName = item.getName().substring(item.getName().lastIndexOf("\\")+1);
// 拿到文件的扩展名
String ext = fileName.substring(fileName.lastIndexOf(".")+1);
/*
if (!types.contains(ext)) {
request.setAttribute("message", "本系统不支持" + ext + "这种类型");
request.getRequestDispatcher("/message.jsp").forward(request, response);
return;
}
*/
InputStream in = item.getInputStream();
int len = 0;
byte[] buffer = new byte[1024];
// FileOutputStream out = new FileOutputStream("c:\\"+fileName);
// FileOutputStream out = new FileOutputStream(this.getServletContext().getRealPath("/upload") + "\\" + fileName);
FileOutputStream out = new FileOutputStream(this.getServletContext().getRealPath("/WEB-INF/upload") + "\\" + fileName);
while ((len=in.read(buffer)) > 0) {
out.write(buffer, 0, len);
}
in.close();
out.close();
/*
* 上传文件完了之后,删除临时文件,
* 千万注意:这句代码一定要放在流关闭之后,否则,还有流和它相关联,那就删除不掉临时文件,
* 为了确保流关闭、删除掉临时文件,最好把这些代码放到finally代码块中。
*/
item.delete();
}
}
} catch (FileUploadBase.FileSizeLimitExceededException e) {
e.printStackTrace();
request.setAttribute("message", "文件大小不能超过5M");
request.getRequestDispatcher("/message.jsp").forward(request, response);
return;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
为了通过测试,我们将代码:
if (!types.contains(ext)) {
request.setAttribute("message", "本系统不支持" + ext + "这种类型");
request.getRequestDispatcher("/message.jsp").forward(request, response);
return;
}
注释掉。
再只上传一个文件进行测试,此时又会出现这样的异常:
究其原因是下面这句代码有错误:
FileOutputStream out = new FileOutputStream(this.getServletContext().getRealPath("/WEB-INF/upload") + "\\" + fileName);
由于fileName是一个空字符串,所以这句代码的意思就是往一个目录里面写数据,那是肯定不行的。因此UploadServlet的代码又要修改为:
public class UploadServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// List<String> types = Arrays.asList(".jpg",".gif",".avi",".txt");
List<String> types = Arrays.asList("jpg","gif","avi","txt");
// request.setCharacterEncoding("UTF-8");
try {
DiskFileItemFactory factory = new DiskFileItemFactory();
factory.setSizeThreshold(1024*1024);
factory.setRepository(new File(this.getServletContext().getRealPath("/temp")));
ServletFileUpload upload = new ServletFileUpload(factory);
// 限制上传文件的大小
upload.setFileSizeMax(1024*1024*5); // 只要超出5M,for循环在解析的时候就会抛异常
// 提交的表单类型不是multipart/form-data,没必要用解析器进行解析数据,按照传统方式获取表单数据
if (!upload.isMultipartContent(request)) {
// 按照传统方式获取表单数据
request.getParameter("username");
blabla......
return;
}
// 解决上传文件的中文乱码问题,设置解析器的编码,到底设什么编码,也不能瞎写,一定要看表单的数据是以什么编码提交的!
upload.setHeaderEncoding("UTF-8");
List<FileItem> list = upload.parseRequest(request);
for (FileItem item : list) {
if (item.isFormField()) {
// 为普通输入项的数据
String inputName = item.getFieldName();
String inputValue = item.getString("UTF-8");
// inputValue = new String(inputValue.getBytes("ISO8859-1"), "UTF-8");
System.out.println(inputName + "=" + inputValue);
} else {
// 代表当前处理的item里面封装的是上传文件
String fileName = item.getName().substring(item.getName().lastIndexOf("\\")+1);
if (fileName == null || fileName.trim().equals("")) {
continue;
}
// 拿到文件的扩展名
String ext = fileName.substring(fileName.lastIndexOf(".")+1);
if (!types.contains(ext)) {
request.setAttribute("message", "本系统不支持" + ext + "这种类型");
request.getRequestDispatcher("/message.jsp").forward(request, response);
return;
}
InputStream in = item.getInputStream();
int len = 0;
byte[] buffer = new byte[1024];
// FileOutputStream out = new FileOutputStream("c:\\"+fileName);
// FileOutputStream out = new FileOutputStream(this.getServletContext().getRealPath("/upload") + "\\" + fileName);
FileOutputStream out = new FileOutputStream(this.getServletContext().getRealPath("/WEB-INF/upload") + "\\" + fileName);
while ((len=in.read(buffer)) > 0) {
out.write(buffer, 0, len);
}
in.close();
out.close();
/*
* 上传文件完了之后,删除临时文件,
* 千万注意:这句代码一定要放在流关闭之后,否则,还有流和它相关联,那就删除不掉临时文件,
* 为了确保流关闭、删除掉临时文件,最好把这些代码放到finally代码块中。
*/
item.delete();
}
}
} catch (FileUploadBase.FileSizeLimitExceededException e) {
e.printStackTrace();
request.setAttribute("message", "文件大小不能超过5M");
request.getRequestDispatcher("/message.jsp").forward(request, response);
return;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
为防止文件覆盖的现象发生,要为上传文件产生一个唯一的文件名
我们在上传文件系统的时候,要考虑到多用户上传相同文件名的文件,而导致文件覆盖的情况发生的问题。为了避免上传文件的覆盖,程序在保存上传文件时,要为每一个文件生成一个唯一的文件名。此时UploadServlet的代码又应修改为:
public class UploadServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// List<String> types = Arrays.asList(".jpg",".gif",".avi",".txt");
List<String> types = Arrays.asList("jpg","gif","avi","txt");
// request.setCharacterEncoding("UTF-8");
try {
DiskFileItemFactory factory = new DiskFileItemFactory();
factory.setSizeThreshold(1024*1024);
factory.setRepository(new File(this.getServletContext().getRealPath("/temp")));
ServletFileUpload upload = new ServletFileUpload(factory);
// 限制上传文件的大小
upload.setFileSizeMax(1024*1024*5); // 只要超出5M,for循环在解析的时候就会抛异常
// 提交的表单类型不是multipart/form-data,没必要用解析器进行解析数据,按照传统方式获取表单数据
if (!upload.isMultipartContent(request)) {
// 按照传统方式获取表单数据
request.getParameter("username");
blabla......
return;
}
// 解决上传文件的中文乱码问题,设置解析器的编码,到底设什么编码,也不能瞎写,一定要看表单的数据是以什么编码提交的!
upload.setHeaderEncoding("UTF-8");
List<FileItem> list = upload.parseRequest(request);
for (FileItem item : list) {
if (item.isFormField()) {
// 为普通输入项的数据
String inputName = item.getFieldName();
String inputValue = item.getString("UTF-8");
// inputValue = new String(inputValue.getBytes("ISO8859-1"), "UTF-8");
System.out.println(inputName + "=" + inputValue);
} else {
// 代表当前处理的item里面封装的是上传文件
String fileName = item.getName().substring(item.getName().lastIndexOf("\\")+1);
if (fileName == null || fileName.trim().equals("")) {
continue;
}
// 拿到文件的扩展名
String ext = fileName.substring(fileName.lastIndexOf(".")+1);
if (!types.contains(ext)) {
request.setAttribute("message", "本系统不支持" + ext + "这种类型");
request.getRequestDispatcher("/message.jsp").forward(request, response);
return;
}
InputStream in = item.getInputStream();
int len = 0;
byte[] buffer = new byte[1024];
// 产生文件的保存目录
String savePath = this.getServletContext().getRealPath("/WEB-INF/upload");
// 得到保存在服务器中唯一的文件名
String saveFileName = generateFileName(fileName);
FileOutputStream out = new FileOutputStream(savePath + File.separator + saveFileName);
while ((len=in.read(buffer)) > 0) {
out.write(buffer, 0, len);
}
in.close();
out.close();
/*
* 上传文件完了之后,删除临时文件,
* 千万注意:这句代码一定要放在流关闭之后,否则,还有流和它相关联,那就删除不掉临时文件,
* 为了确保流关闭、删除掉临时文件,最好把这些代码放到finally代码块中。
*/
item.delete();
}
}
} catch (FileUploadBase.FileSizeLimitExceededException e) {
e.printStackTrace();
request.setAttribute("message", "文件大小不能超过5M");
request.getRequestDispatcher("/message.jsp").forward(request, response);
return;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public String generateFileName(String fileName) {
// 4de727e8-2579-477f-a4ae-658355f107fe
return UUID.randomUUID().toString() + "_" + fileName;
}
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
一般来说,这句代码
FileOutputStream out = new FileOutputStream(savePath + File.separator + saveFileName);
我们应该写为:
FileOutputStream out = new FileOutputStream(savePath + "\\" + saveFileName);
为何我们不这样写了,因为考虑到了平台无关性,我们一般都是在Windows系统上做开发,然后再把项目部署到Linux系统中,为了更通用,所以我们要使用File.separator
来代替各个操作系统中的分隔符。
我们上传一个文件进行测试,可以发现在诸如F:\Tomcat_8\apache-tomcat-8.0.36\webapps\day18\WEB-INF\upload这样的目录下找到上传的文件,如下:
为防止一个目录下面出现太多文件,要使用hash算法打散存储
如果一个windows目录下面文件数量太大,目录的访问速度就会很慢,在windows里面,建议一个目录下面最多不要超过1000个文件。
在做这样一个文件上传系统时,我们也要考虑此种情况。为防止单个目录下文件过多,影响文件读写速度,处理上传文件的程序应根据可能的文件上传总量,选择合适的目录结构生成算法,将上传文件分散存储。我们选择的目录结构生成算法是这样的:
根据保存在服务器中文件的文件名,比如cac1c5d9-b492-4cd9-a724-ec06eb4a6a5d_上传文件1.txt
,利用hashCode()方法算出这样一串字符串的hashCode值,即得到该字符串在内存中的地址,如121221
。这样的数在计算机中是如何存储的呢?大概就是这样的形式:0010 0011 0011 0101 1100 0111 0010 0111
。
- 取其低4位(范围:0~15),构建一个目录(一级目录),这样就会有16个目录(0目录~15目录),每个目录保存1000份文件,总共就可保存16000份文件;
- 如若嫌弃保存的文件数太小,可再取其4~8位(范围:0~15),构建一个目录(二级目录),这样就会有16²个目录,每个目录保存1000份文件,总共就可保存256000份文件;
- ……
- 以此类推,最后取其高4位(范围:0~15),构建一个目录(八级目录),这样就会有16ⁿ(n=8)个目录,每个目录保存1000份文件,总共就可保存
16ⁿ(n=8)X1000
份文件,足以保存够多的文件了。
这样,UploadServlet的代码又应修改为:
public class UploadServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// List<String> types = Arrays.asList(".jpg",".gif",".avi",".txt");
List<String> types = Arrays.asList("jpg","gif","avi","txt");
// request.setCharacterEncoding("UTF-8");
try {
DiskFileItemFactory factory = new DiskFileItemFactory();
factory.setSizeThreshold(1024*1024);
factory.setRepository(new File(this.getServletContext().getRealPath("/temp")));
ServletFileUpload upload = new ServletFileUpload(factory);
// 限制上传文件的大小
upload.setFileSizeMax(1024*1024*5); // 只要超出5M,for循环在解析的时候就会抛异常
// 提交的表单类型不是multipart/form-data,没必要用解析器进行解析数据,按照传统方式获取表单数据
if (!upload.isMultipartContent(request)) {
// 按照传统方式获取表单数据
request.getParameter("username");
blabla......
return;
}
// 解决上传文件的中文乱码问题,设置解析器的编码,到底设什么编码,也不能瞎写,一定要看表单的数据是以什么编码提交的!
upload.setHeaderEncoding("UTF-8");
List<FileItem> list = upload.parseRequest(request);
for (FileItem item : list) {
if (item.isFormField()) {
// 为普通输入项的数据
String inputName = item.getFieldName();
String inputValue = item.getString("UTF-8");
// inputValue = new String(inputValue.getBytes("ISO8859-1"), "UTF-8");
System.out.println(inputName + "=" + inputValue);
} else {
// 代表当前处理的item里面封装的是上传文件
String fileName = item.getName().substring(item.getName().lastIndexOf("\\")+1);
if (fileName == null || fileName.trim().equals("")) {
continue;
}
// 拿到文件的扩展名
String ext = fileName.substring(fileName.lastIndexOf(".")+1);
if (!types.contains(ext)) {
request.setAttribute("message", "本系统不支持" + ext + "这种类型");
request.getRequestDispatcher("/message.jsp").forward(request, response);
return;
}
InputStream in = item.getInputStream();
int len = 0;
byte[] buffer = new byte[1024];
// 得到保存在服务器中唯一的文件名
String saveFileName = generateFileName(fileName);
// 产生文件的保存目录
String savePath = generateSavePath(this.getServletContext().getRealPath("/WEB-INF/upload"), saveFileName);
FileOutputStream out = new FileOutputStream(savePath + File.separator + saveFileName);
while ((len=in.read(buffer)) > 0) {
out.write(buffer, 0, len);
}
in.close();
out.close();
/*
* 上传文件完了之后,删除临时文件,
* 千万注意:这句代码一定要放在流关闭之后,否则,还有流和它相关联,那就删除不掉临时文件,
* 为了确保流关闭、删除掉临时文件,最好把这些代码放到finally代码块中。
*/
item.delete();
}
}
} catch (FileUploadBase.FileSizeLimitExceededException e) {
e.printStackTrace();
request.setAttribute("message", "文件大小不能超过5M");
request.getRequestDispatcher("/message.jsp").forward(request, response);
return;
} catch (Exception e) {
throw new RuntimeException(e);
}
request.setAttribute("message", "上传成功!!!");
request.getRequestDispatcher("/message.jsp").forward(request, response);
}
public String generateSavePath(String path, String fileName) {
int hashCode = fileName.hashCode(); // 得到字符串在内存中的地址,如121221
int dir1 = hashCode & 15; // int dir1 = hashCode & 0xf; 代表一级目录
int dir2 = (hashCode >> 4) & 0xf; // 代表二级目录
// 用户第一次上传文件,此savePath目录在服务器的硬盘里原本是没有的,所以应将其创建出来
String savePath = path + File.separator + dir1 + File.separator + dir2;
File file = new File(savePath);
if (!file.exists()) {
file.mkdirs(); // 创建多级目录用mkdirs()方法
}
return savePath;
}
public String generateFileName(String fileName) {
// 4de727e8-2579-477f-a4ae-658355f107fe
return UUID.randomUUID().toString() + "_" + fileName;
}
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
测试完了之后,我们会发现上传的文件在服务器中找起来非常不容易,但是这又不是让人去查找,我们是写程序去查找,所以这根本就不算是什么事。
监听上传进度
我们在做文件上传系统时,用户上传文件时,一般都会有那种进度条。但是要在前台页面做出这样的上传的进度条,没有学过Ajax技术,是无法完成的,所以我们只在Eclipse控制台打印上传的信息。要做到这一点,就要给解析器注册一个监听器,那么UploadServlet的代码应修改为:
public class UploadServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// List<String> types = Arrays.asList(".jpg",".gif",".avi",".txt");
List<String> types = Arrays.asList("jpg","gif","avi","txt");
// request.setCharacterEncoding("UTF-8");
try {
DiskFileItemFactory factory = new DiskFileItemFactory();
factory.setSizeThreshold(1024*1024);
factory.setRepository(new File(this.getServletContext().getRealPath("/temp")));
ServletFileUpload upload = new ServletFileUpload(factory);
upload.setProgressListener(new ProgressListener() {
// update方法一定要由解析器来调用
@Override
public void update(long pBytesRead, long pContentLength, int pItems) {
System.out.println("当前已解析:" + pBytesRead);
}
});
// 限制上传文件的大小
upload.setFileSizeMax(1024*1024*5); // 只要超出5M,for循环在解析的时候就会抛异常
// 提交的表单类型不是multipart/form-data,没必要用解析器进行解析数据,按照传统方式获取表单数据
if (!upload.isMultipartContent(request)) {
// 按照传统方式获取表单数据
request.getParameter("username");
blabla......
return;
}
// 解决上传文件的中文乱码问题,设置解析器的编码,到底设什么编码,也不能瞎写,一定要看表单的数据是以什么编码提交的!
upload.setHeaderEncoding("UTF-8");
List<FileItem> list = upload.parseRequest(request);
for (FileItem item : list) {
if (item.isFormField()) {
// 为普通输入项的数据
String inputName = item.getFieldName();
String inputValue = item.getString("UTF-8");
// inputValue = new String(inputValue.getBytes("ISO8859-1"), "UTF-8");
System.out.println(inputName + "=" + inputValue);
} else {
// 代表当前处理的item里面封装的是上传文件
String fileName = item.getName().substring(item.getName().lastIndexOf("\\")+1);
if (fileName == null || fileName.trim().equals("")) {
continue;
}
// 拿到文件的扩展名
String ext = fileName.substring(fileName.lastIndexOf(".")+1);
if (!types.contains(ext)) {
request.setAttribute("message", "本系统不支持" + ext + "这种类型");
request.getRequestDispatcher("/message.jsp").forward(request, response);
return;
}
InputStream in = item.getInputStream();
int len = 0;
byte[] buffer = new byte[1024];
// 得到保存在服务器中唯一的文件名
String saveFileName = generateFileName(fileName);
// 产生文件的保存目录
String savePath = generateSavePath(this.getServletContext().getRealPath("/WEB-INF/upload"), saveFileName);
FileOutputStream out = new FileOutputStream(savePath + File.separator + saveFileName);
while ((len=in.read(buffer)) > 0) {
out.write(buffer, 0, len);
}
in.close();
out.close();
/*
* 上传文件完了之后,删除临时文件,
* 千万注意:这句代码一定要放在流关闭之后,否则,还有流和它相关联,那就删除不掉临时文件,
* 为了确保流关闭、删除掉临时文件,最好把这些代码放到finally代码块中。
*/
item.delete();
}
}
} catch (FileUploadBase.FileSizeLimitExceededException e) {
e.printStackTrace();
request.setAttribute("message", "文件大小不能超过5M");
request.getRequestDispatcher("/message.jsp").forward(request, response);
return;
} catch (Exception e) {
throw new RuntimeException(e);
}
request.setAttribute("message", "上传成功!!!");
request.getRequestDispatcher("/message.jsp").forward(request, response);
}
public String generateSavePath(String path, String fileName) {
int hashCode = fileName.hashCode(); // 得到字符串在内存中的地址,如121221
int dir1 = hashCode & 15; // int dir1 = hashCode & 0xf; 代表一级目录
int dir2 = (hashCode >> 4) & 0xf; // 代表二级目录
// 用户第一次上传文件,此savePath目录在服务器的硬盘里原本是没有的,所以应将其创建出来
String savePath = path + File.separator + dir1 + File.separator + dir2;
File file = new File(savePath);
if (!file.exists()) {
file.mkdirs(); // 创建多级目录用mkdirs()方法
}
return savePath;
}
public String generateFileName(String fileName) {
// 4de727e8-2579-477f-a4ae-658355f107fe
return UUID.randomUUID().toString() + "_" + fileName;
}
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
我们上传一个文件,可以看到在Eclipse的控制台中打印如下信息:
当前已解析:4096
当前已解析:7625
当前已解析:11675
当前已解析:15725
当前已解析:15817
当前已解析:19867
当前已解析:23917
当前已解析:24009
当前已解析:28059
当前已解析:32109
当前已解析:32201
当前已解析:36251
当前已解析:40301
当前已解析:40393
当前已解析:44443
当前已解析:48493
当前已解析:48585
当前已解析:52635
当前已解析:56685
当前已解析:56777
当前已解析:60827
当前已解析:64877
当前已解析:64969
当前已解析:69019
当前已解析:73069
当前已解析:73161
当前已解析:77211
当前已解析:81261
当前已解析:81353
当前已解析:85403
当前已解析:89453
当前已解析:89545
当前已解析:93595
当前已解析:97645
当前已解析:97737
当前已解析:101787
当前已解析:105837
当前已解析:105929
当前已解析:109979
当前已解析:112109
千万要注意,解析器注册监听器的代码不能放在代码
List<FileItem> list = upload.parseRequest(request);
后面,因为这句代码就是在解析,别人都解析完了,你才去监听,那还有个屁用!所以监听器一定要写在解析之前。
最后多一嘴,如果我们希望上传进度条能够均匀地增长,即每上传100M的数据,进度条就增长,可以参考Commons-fileupload组件的User guide,在User guide中就有这样的代码:
//Create a progress listener
ProgressListener progressListener = new ProgressListener(){
private long megaBytes = -1;
public void update(long pBytesRead, long pContentLength, int pItems) {
long mBytes = pBytesRead / 1000000;
if (megaBytes == mBytes) {
return;
}
megaBytes = mBytes;
System.out.println("We are currently reading item " + pItems);
if (pContentLength == -1) {
System.out.println("So far, " + pBytesRead + " bytes have been read.");
} else {
System.out.println("So far, " + pBytesRead + " of " + pContentLength
+ " bytes have been read.");
}
}
};
在web页面中动态添加上传输入项
有些文件上传系统有这样的需求:要在jsp页面中动态地添加文件上传输入项。要实现此需求,我们就要写JavaScript代码了,其核心思想是:每次动态增加一个文件上传输入框,都把它和删除按纽放置在一个单独的div中,并对删除按纽的onclick事件进行响应,使之删除按纽所在的div。
我们以此编写一个这样的jsp页面。
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
<script type="text/javascript">
function addfile() {
var files = document.getElementById("files");
var input = document.createElement("input");
input.type="file";
input.name="file1";
var btn = document.createElement("input");
btn.type="button";
btn.value="删除";
btn.onclick = function del() { // 不要写成delete,类似关键字
// this代表button按钮自己
this.parentNode.parentNode.removeChild(this.parentNode);
}
var div = document.createElement("div");
div.appendChild(input);
div.appendChild(btn);
files.appendChild(div);
}
</script>
</head>
<body>
<form action="/day18/UploadServlet2" enctype="multipart/form-data" method="post">
<table>
<tr>
<td>上传用户</td>
<td>
<input type="text" name="username">
</td>
</tr>
<tr>
<td>上传文件</td>
<td>
<input type="button" value="添加上传文件" onclick="addfile()">
</td>
</tr>
<tr>
<td></td>
<td>
<div id="files"></div>
</td>
</tr>
<tr>
<td></td>
<td>
<input type="submit" value="上传">
</td>
</tr>
</table>
</form>
</body>
</html>
测试以上jsp页面,如下:
终于,我们把处理文件上传所需要注意的细节都介绍完了,总算不错了,给自己一个鼓励!