• 简介

  文件上传和下载是java web中常见的操作,文件上传主要是将文件通过IO流传放到服务器的某一个特定的文件夹下,而文件下载则是与文件上传相反,将文件从服务器的特定的文件夹下的文件通过IO流下载到本地。

  对于文件上传,浏览器在上传的过程中是将文件以流的形式提交到服务器端的,如果直接使用Servlet获取上传文件的输入流然后再解析里面的请求参数是比较麻烦,所以一般选择采用apache的开源工具common-fileupload这个文件上传组件。这个common-fileupload上传组件的jar包可以去apache官网上面下载,也可以在struts的lib文件夹下面找到,struts上传的功能就是基于这个实现的。common-fileupload是依赖于common-io这个包的,所以还需要下载这个包。

  • 文件上传

  1、文件上传页面和消息提示页面

  upload.jsp页面的代码如下:

  1. <%@ page language="java" pageEncoding="UTF-8"%>
  2. <!DOCTYPE HTML>
  3. <html>
  4. <head>
  5. <title>文件上传</title>
  6. </head>
  7.  
  8. <body>
  9. <form action="${pageContext.request.contextPath}/servlet/uploadHandleServlet2" enctype="multipart/form-data" method="post" 上传用户:<input type="text" name="username"><br/>
  10. 上传文件1:<input type="file" name="file1"><br/>
  11. 上传文件2:<input type="file" name="file2"><br/>
  12. <input type="submit" value="提交">
  13. </form>
  14. </body>
  15. </html>

  在文件上传的页面要用enctype="multipart/form-data" method="post"来表示进行文件上传。

  2、处理文件上传的Servlet

  1. public class UploadHandleServlet extends HttpServlet{
  2.  
  3. @Override
  4. protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
  5. //得到上传文件的保存目录,将上传的文件存放于WEB-INF目录下,不允许外界直接访问,保证上传文件的安全
  6. String savePath = this.getServletContext().getRealPath("/WEB-INF/upload");
  7. File file = new File(savePath);
  8. if(!file.exists()&&!file.isDirectory()){
  9. System.out.println("目录或文件不存在!");
  10. file.mkdir();
  11. }
  12. //消息提示
  13. String message = "";
  14. try {
  15. //使用Apache文件上传组件处理文件上传步骤:
  16. //1、创建一个DiskFileItemFactory工厂
  17. DiskFileItemFactory diskFileItemFactory = new DiskFileItemFactory();
  18. //2、创建一个文件上传解析器
  19. ServletFileUpload fileUpload = new ServletFileUpload(diskFileItemFactory);
  20. //解决上传文件名的中文乱码
  21. fileUpload.setHeaderEncoding("UTF-8");
  22. //3、判断提交上来的数据是否是上传表单的数据
  23. if(!fileUpload.isMultipartContent(request)){
  24. //按照传统方式获取数据
  25. return;
  26. }
  27. //4、使用ServletFileUpload解析器解析上传数据,解析结果返回的是一个List<FileItem>集合,每一个FileItem对应一个Form表单的输入项
  28. List<FileItem> list = fileUpload.parseRequest(request);
  29. for (FileItem item : list) {
  30. //如果fileitem中封装的是普通输入项的数据
  31. if(item.isFormField()){
  32. String name = item.getFieldName();
  33. //解决普通输入项的数据的中文乱码问题
  34. String value = item.getString("UTF-8");
  35. String value1 = new String(name.getBytes("iso8859-1"),"UTF-8");
  36. System.out.println(name+" "+value);
  37. System.out.println(name+" "+value1);
  38. }else{
  39. //如果fileitem中封装的是上传文件,得到上传的文件名称,
  40. String fileName = item.getName();
  41. System.out.println(fileName);
  42. if(fileName==null||fileName.trim().equals("")){
  43. continue;
  44. }
  45. //注意:不同的浏览器提交的文件名是不一样的,有些浏览器提交上来的文件名是带有路径的,如: c:\a\b\1.txt,而有些只是单纯的文件名,如:1.txt
  46. //处理获取到的上传文件的文件名的路径部分,只保留文件名部分
  47. fileName = fileName.substring(fileName.lastIndexOf(File.separator)+1);
  48. //获取item中的上传文件的输入流
  49. InputStream is = item.getInputStream();
  50. //创建一个文件输出流
  51. FileOutputStream fos = new FileOutputStream(savePath+File.separator+fileName);
  52. //创建一个缓冲区
  53. byte buffer[] = new byte[1024];
  54. //判断输入流中的数据是否已经读完的标识
  55. int length = 0;
  56. //循环将输入流读入到缓冲区当中,(len=in.read(buffer))>0就表示in里面还有数据
  57. while((length = is.read(buffer))>0){
  58. //使用FileOutputStream输出流将缓冲区的数据写入到指定的目录(savePath + "\\" + filename)当中
  59. fos.write(buffer, 0, length);
  60. }
  61. //关闭输入流
  62. is.close();
  63. //关闭输出流
  64. fos.close();
  65. //删除处理文件上传时生成的临时文件
  66. item.delete();
  67. message = "文件上传成功";
  68. }
  69. }
  70. } catch (FileUploadException e) {
  71. // TODO Auto-generated catch block
  72. e.printStackTrace();
  73. message = "文件上传失败";
  74. }
  75. request.setAttribute("message",message);
  76. request.getRequestDispatcher("/message.jsp").forward(request, response);
  77. }
  78.  
  79. @Override
  80. protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
  81. doGet(request, response);
  82. }
  83.  
  84. }

  3、文件上传的细节

  上述的代码虽然可以成功将文件上传到服务器上面的指定目录当中,但是文件上传功能有许多需要注意的小细节问题,以下列出的几点需要特别注意的:

  (1)、为保证服务器安全,上传文件应该放在外界无法直接访问的目录下,比如放于WEB-INF目录下。

  (2)、为防止文件覆盖的现象发生,要为上传文件产生一个唯一的文件名。

  (3)、为防止一个目录下面出现太多文件,要使用hash算法打散存储。

  (4)、要限制上传文件的最大值。

  (5)、要限制上传文件的类型,在收到上传文件名时,判断后缀名是否合法。

  4、改进后的servlet

  1. public class UploadHandleServlet1 extends HttpServlet{
  2.  
  3. @Override
  4. protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
  5. //得到上传文件的保存目录,将上传的文件存放于WEB-INF目录下,不允许外界直接访问,保证上传文件的安全
  6. String savePath = this.getServletContext().getRealPath("/WEB-INF/upload");
  7. //上传时生成的临时文件保存目录
  8. String tempPath = this.getServletContext().getRealPath("/WEB-INF/temp");
  9. File file = new File(tempPath);
  10. if(!file.exists()&&!file.isDirectory()){
  11. System.out.println("目录或文件不存在!");
  12. file.mkdir();
  13. }
  14. //消息提示
  15. String message = "";
  16. try {
  17. //使用Apache文件上传组件处理文件上传步骤:
  18. //1、创建一个DiskFileItemFactory工厂
  19. DiskFileItemFactory diskFileItemFactory = new DiskFileItemFactory();
  20. //设置工厂的缓冲区的大小,当上传的文件大小超过缓冲区的大小时,就会生成一个临时文件存放到指定的临时目录当中。
  21. diskFileItemFactory.setSizeThreshold(1024*100);
  22. //设置上传时生成的临时文件的保存目录
  23. diskFileItemFactory.setRepository(file);
  24. //2、创建一个文件上传解析器
  25. ServletFileUpload fileUpload = new ServletFileUpload(diskFileItemFactory);
  26. //解决上传文件名的中文乱码
  27. fileUpload.setHeaderEncoding("UTF-8");
  28. //监听文件上传进度
  29. fileUpload.setProgressListener(new ProgressListener(){
  30. public void update(long pBytesRead, long pContentLength, int arg2) {
  31. System.out.println("文件大小为:" + pContentLength + ",当前已处理:" + pBytesRead);
  32. }
  33. });
  34. //3、判断提交上来的数据是否是上传表单的数据
  35. if(!fileUpload.isMultipartContent(request)){
  36. //按照传统方式获取数据
  37. return;
  38. }
  39. //设置上传单个文件的大小的最大值,目前是设置为1024*1024字节,也就是1MB
  40. fileUpload.setFileSizeMax(1024*1024);
  41. //设置上传文件总量的最大值,最大值=同时上传的多个文件的大小的最大值的和,目前设置为10MB
  42. fileUpload.setSizeMax(1024*1024*10);
  43. //4、使用ServletFileUpload解析器解析上传数据,解析结果返回的是一个List<FileItem>集合,每一个FileItem对应一个Form表单的输入项
  44. List<FileItem> list = fileUpload.parseRequest(request);
  45. for (FileItem item : list) {
  46. //如果fileitem中封装的是普通输入项的数据
  47. if(item.isFormField()){
  48. String name = item.getFieldName();
  49. //解决普通输入项的数据的中文乱码问题
  50. String value = item.getString("UTF-8");
  51. String value1 = new String(name.getBytes("iso8859-1"),"UTF-8");
  52. System.out.println(name+" "+value);
  53. System.out.println(name+" "+value1);
  54. }else{
  55. //如果fileitem中封装的是上传文件,得到上传的文件名称,
  56. String fileName = item.getName();
  57. System.out.println(fileName);
  58. if(fileName==null||fileName.trim().equals("")){
  59. continue;
  60. }
  61. //注意:不同的浏览器提交的文件名是不一样的,有些浏览器提交上来的文件名是带有路径的,如: c:\a\b\1.txt,而有些只是单纯的文件名,如:1.txt
  62. //处理获取到的上传文件的文件名的路径部分,只保留文件名部分
  63. fileName = fileName.substring(fileName.lastIndexOf(File.separator)+1);
  64. //得到上传文件的扩展名
  65. String fileExtName = fileName.substring(fileName.lastIndexOf(".")+1);
  66. if("zip".equals(fileExtName)||"rar".equals(fileExtName)||"tar".equals(fileExtName)||"jar".equals(fileExtName)){
  67. request.setAttribute("message", "上传文件的类型不符合!!!");
  68. request.getRequestDispatcher("/message.jsp").forward(request, response);
  69. return;
  70. }
  71. //如果需要限制上传的文件类型,那么可以通过文件的扩展名来判断上传的文件类型是否合法
  72. System.out.println("上传文件的扩展名为:"+fileExtName);
  73. //获取item中的上传文件的输入流
  74. InputStream is = item.getInputStream();
  75. //得到文件保存的名称
  76. fileName = mkFileName(fileName);
  77. //得到文件保存的路径
  78. String savePathStr = mkFilePath(savePath, fileName);
  79. System.out.println("保存路径为:"+savePathStr);
  80. //创建一个文件输出流
  81. FileOutputStream fos = new FileOutputStream(savePathStr+File.separator+fileName);
  82. //创建一个缓冲区
  83. byte buffer[] = new byte[1024];
  84. //判断输入流中的数据是否已经读完的标识
  85. int length = 0;
  86. //循环将输入流读入到缓冲区当中,(len=in.read(buffer))>0就表示in里面还有数据
  87. while((length = is.read(buffer))>0){
  88. //使用FileOutputStream输出流将缓冲区的数据写入到指定的目录(savePath + "\\" + filename)当中
  89. fos.write(buffer, 0, length);
  90. }
  91. //关闭输入流
  92. is.close();
  93. //关闭输出流
  94. fos.close();
  95. //删除处理文件上传时生成的临时文件
  96. item.delete();
  97. message = "文件上传成功";
  98. }
  99. }
  100. } catch (FileUploadBase.FileSizeLimitExceededException e) {
  101. e.printStackTrace();
  102. request.setAttribute("message", "单个文件超出最大值!!!");
  103. request.getRequestDispatcher("/message.jsp").forward(request, response);
  104. return;
  105. }catch (FileUploadBase.SizeLimitExceededException e) {
  106. e.printStackTrace();
  107. request.setAttribute("message", "上传文件的总的大小超出限制的最大值!!!");
  108. request.getRequestDispatcher("/message.jsp").forward(request, response);
  109. return;
  110. }catch (FileUploadException e) {
  111. // TODO Auto-generated catch block
  112. e.printStackTrace();
  113. message = "文件上传失败";
  114. }
  115. request.setAttribute("message",message);
  116. request.getRequestDispatcher("/message.jsp").forward(request, response);
  117. }
  118.  
  119. @Override
  120. protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
  121. doGet(request, response);
  122. }
  123. //生成上传文件的文件名,文件名以:uuid+"_"+文件的原始名称
  124. public String mkFileName(String fileName){
  125. return UUID.randomUUID().toString()+"_"+fileName;
  126. }
  127. public String mkFilePath(String savePath,String fileName){
  128. //得到文件名的hashCode的值,得到的就是filename这个字符串对象在内存中的地址
  129. int hashcode = fileName.hashCode();
  130. int dir1 = hashcode&0xf;
  131. int dir2 = (hashcode&0xf0)>>4;
  132. //构造新的保存目录
  133. String dir = savePath + "\\" + dir1 + "\\" + dir2;
  134. //File既可以代表文件也可以代表目录
  135. File file = new File(dir);
  136. if(!file.exists()){
  137. file.mkdirs();
  138. }
  139. return dir;
  140. }
  141. }

  5、如果在文件上传中IO流成为了系统的性能瓶颈,可以考虑使用NIO来提高性能。改进servlet代码如下:

  1. public class UploadHandleServlet2 extends HttpServlet{
  2.  
  3. @Override
  4. protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
  5. //得到上传文件的保存目录,将上传的文件存放于WEB-INF目录下,不允许外界直接访问,保证上传文件的安全
  6. String savePath = this.getServletContext().getRealPath("/WEB-INF/upload");
  7. //上传时生成的临时文件保存目录
  8. String tempPath = this.getServletContext().getRealPath("/WEB-INF/temp");
  9. File file = new File(tempPath);
  10. if(!file.exists()&&!file.isDirectory()){
  11. System.out.println("目录或文件不存在!");
  12. file.mkdir();
  13. }
  14. //消息提示
  15. String message = "";
  16. try {
  17. //使用Apache文件上传组件处理文件上传步骤:
  18. //1、创建一个DiskFileItemFactory工厂
  19. DiskFileItemFactory diskFileItemFactory = new DiskFileItemFactory();
  20. //设置工厂的缓冲区的大小,当上传的文件大小超过缓冲区的大小时,就会生成一个临时文件存放到指定的临时目录当中。
  21. diskFileItemFactory.setSizeThreshold(1024*100);
  22. //设置上传时生成的临时文件的保存目录
  23. diskFileItemFactory.setRepository(file);
  24. //2、创建一个文件上传解析器
  25. ServletFileUpload fileUpload = new ServletFileUpload(diskFileItemFactory);
  26. //解决上传文件名的中文乱码
  27. fileUpload.setHeaderEncoding("UTF-8");
  28. //监听文件上传进度
  29. fileUpload.setProgressListener(new ProgressListener(){
  30. public void update(long pBytesRead, long pContentLength, int arg2) {
  31. System.out.println("文件大小为:" + pContentLength + ",当前已处理:" + pBytesRead);
  32. }
  33. });
  34. //3、判断提交上来的数据是否是上传表单的数据
  35. if(!fileUpload.isMultipartContent(request)){
  36. //按照传统方式获取数据
  37. return;
  38. }
  39. //设置上传单个文件的大小的最大值,目前是设置为1024*1024字节,也就是1MB
  40. fileUpload.setFileSizeMax(1024*1024);
  41. //设置上传文件总量的最大值,最大值=同时上传的多个文件的大小的最大值的和,目前设置为10MB
  42. fileUpload.setSizeMax(1024*1024*10);
  43. //4、使用ServletFileUpload解析器解析上传数据,解析结果返回的是一个List<FileItem>集合,每一个FileItem对应一个Form表单的输入项
  44. List<FileItem> list = fileUpload.parseRequest(request);
  45. for (FileItem item : list) {
  46. //如果fileitem中封装的是普通输入项的数据
  47. if(item.isFormField()){
  48. String name = item.getFieldName();
  49. //解决普通输入项的数据的中文乱码问题
  50. String value = item.getString("UTF-8");
  51. String value1 = new String(name.getBytes("iso8859-1"),"UTF-8");
  52. System.out.println(name+" "+value);
  53. System.out.println(name+" "+value1);
  54. }else{
  55. //如果fileitem中封装的是上传文件,得到上传的文件名称,
  56. String fileName = item.getName();
  57. System.out.println(fileName);
  58. if(fileName==null||fileName.trim().equals("")){
  59. continue;
  60. }
  61. //注意:不同的浏览器提交的文件名是不一样的,有些浏览器提交上来的文件名是带有路径的,如: c:\a\b\1.txt,而有些只是单纯的文件名,如:1.txt
  62. //处理获取到的上传文件的文件名的路径部分,只保留文件名部分
  63. fileName = fileName.substring(fileName.lastIndexOf(File.separator)+1);
  64. //得到上传文件的扩展名
  65. String fileExtName = fileName.substring(fileName.lastIndexOf(".")+1);
  66. if("zip".equals(fileExtName)||"rar".equals(fileExtName)||"tar".equals(fileExtName)||"jar".equals(fileExtName)){
  67. request.setAttribute("message", "上传文件的类型不符合!!!");
  68. request.getRequestDispatcher("/message.jsp").forward(request, response);
  69. return;
  70. }
  71. //如果需要限制上传的文件类型,那么可以通过文件的扩展名来判断上传的文件类型是否合法
  72. System.out.println("上传文件的扩展名为:"+fileExtName);
  73. //获取item中的上传文件的输入流
  74. InputStream fis = item.getInputStream();
  75. //得到文件保存的名称
  76. fileName = mkFileName(fileName);
  77. //得到文件保存的路径
  78. String savePathStr = mkFilePath(savePath, fileName);
  79. System.out.println("保存路径为:"+savePathStr);
  80. //创建一个文件输出流
  81. FileOutputStream fos = new FileOutputStream(savePathStr+File.separator+fileName);
  82. //获取读通道
  83. FileChannel readChannel = ((FileInputStream)fis).getChannel();
  84. //获取读通道
  85. FileChannel writeChannel = fos.getChannel();
  86. //创建一个缓冲区
  87. ByteBuffer buffer = ByteBuffer.allocate(1024);
  88. //判断输入流中的数据是否已经读完的标识
  89. int length = 0;
  90. //循环将输入流读入到缓冲区当中,(len=in.read(buffer))>0就表示in里面还有数据
  91. while(true){
  92. buffer.clear();
  93. int len = readChannel.read(buffer);//读入数据
  94. if(len < 0){
  95. break;//读取完毕
  96. }
  97. buffer.flip();
  98. writeChannel.write(buffer);//写入数据
  99. }
  100. //关闭输入流
  101. fis.close();
  102. //关闭输出流
  103. fos.close();
  104. //删除处理文件上传时生成的临时文件
  105. item.delete();
  106. message = "文件上传成功";
  107. }
  108. }
  109. } catch (FileUploadBase.FileSizeLimitExceededException e) {
  110. e.printStackTrace();
  111. request.setAttribute("message", "单个文件超出最大值!!!");
  112. request.getRequestDispatcher("/message.jsp").forward(request, response);
  113. return;
  114. }catch (FileUploadBase.SizeLimitExceededException e) {
  115. e.printStackTrace();
  116. request.setAttribute("message", "上传文件的总的大小超出限制的最大值!!!");
  117. request.getRequestDispatcher("/message.jsp").forward(request, response);
  118. return;
  119. }catch (FileUploadException e) {
  120. // TODO Auto-generated catch block
  121. e.printStackTrace();
  122. message = "文件上传失败";
  123. }
  124. request.setAttribute("message",message);
  125. request.getRequestDispatcher("/message.jsp").forward(request, response);
  126. }
  127.  
  128. @Override
  129. protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
  130. doGet(request, response);
  131. }
  132. //生成上传文件的文件名,文件名以:uuid+"_"+文件的原始名称
  133. public String mkFileName(String fileName){
  134. return UUID.randomUUID().toString()+"_"+fileName;
  135. }
  136. public String mkFilePath(String savePath,String fileName){
  137. //得到文件名的hashCode的值,得到的就是filename这个字符串对象在内存中的地址
  138. int hashcode = fileName.hashCode();
  139. int dir1 = hashcode&0xf;
  140. int dir2 = (hashcode&0xf0)>>4;
  141. //构造新的保存目录
  142. String dir = savePath + "\\" + dir1 + "\\" + dir2;
  143. //File既可以代表文件也可以代表目录
  144. File file = new File(dir);
  145. if(!file.exists()){
  146. file.mkdirs();
  147. }
  148. return dir;
  149. }
  150. }
  • 文件下载

  1、列出提供下载的文件资源

  要将Web应用系统中的文件资源提供给用户进行下载,首先我们要有一个页面列出上传文件目录下的所有文件,当用户点击文件下载超链接时就进行下载操作,编写一个ListFileServlet,用于列出Web应用系统中所有下载文件。

  ListFileServlet代码如下:

  1. public class ListFileServlet extends HttpServlet{
  2. @Override
  3. protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
  4. doPost(request, response);
  5. }
  6. @Override
  7. protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
  8. // TODO Auto-generated method stub
  9. //获取上传文件的目录
  10. String uploadFilePath = this.getServletContext().getRealPath("/WEB-INF/upload");
  11. //存储要下载的文件名
  12. Map<String, String> fileMap = new HashMap<String, String>();
  13. //递归遍历filepath目录下的所有文件和目录,将文件的文件名存储到map集合中
  14. fileList(new File(uploadFilePath),fileMap);
  15. //将Map集合发送到listfile.jsp页面进行显示
  16. request.setAttribute("fileMap", fileMap);
  17. request.getRequestDispatcher("/listfile.jsp").forward(request, response);
  18.  
  19. }
  20. //递归遍历指定目录下的所有文件
  21. public void fileList(File file,Map fileMap){
  22. //如果file代表的不是一个文件,而是一个目录
  23. if(!file.isFile()){
  24. //列出该目录下的所有文件和目录
  25. File[] files = file.listFiles();
  26. //遍历files[]数组
  27. for (File file2 : files) {
  28. System.out.println(file2.getName());
  29. //递归
  30. fileList(file2, fileMap);
  31. }
  32. }else{
  33. /* 处理文件名,上传后的文件是以uuid_文件名的形式去重新命名的,去除文件名的uuid_部分
  34. file.getName().indexOf("_")检索字符串中第一次出现"_"字符的位置,如果文件名类似于:9349249849-88343-8344_阿_凡_达.avi
  35. 那么file.getName().substring(file.getName().indexOf("_")+1)处理之后就可以得到阿_凡_达.avi部分
  36. */
  37. String realName = file.getName().substring(file.getName().lastIndexOf("_")+1);
  38. //file.getName()得到的是文件的原始名称,这个名称是唯一的,因此可以作为key,realName是处理过后的名称,有可能会重复
  39. fileMap.put(file.getName(), realName);
  40. }
  41. }
  42. }

  说明一下,一般文件路径在数据库中保存,然后再数据库中查询结果在页面显示。

  listfile.jsp页面

  1. <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
  2. <%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
  3. <!DOCTYPE HTML>
  4. <html>
  5. <head>
  6. <title>下载文件显示页面</title>
  7. </head>
  8.  
  9. <body>
  10. <!-- 遍历Map集合 -->
  11. <c:forEach var="me" items="${fileMap}">
  12. <c:url value="/servlet/downLoadServlet" var="downurl">
  13. <c:param name="filename" value="${me.key}"></c:param>
  14. </c:url>
  15. ${me.value}<a href="${downurl}">下载</a>
  16. <br/>
  17. </c:forEach>
  18. </body>
  19. </html>

  2、文件下载

  DownLoadServlet的代码如下:

  1. public class DownLoadServlet extends HttpServlet{
  2.  
  3. @Override
  4. protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
  5. //得到要下载的文件名
  6. String fileName = request.getParameter("filename");
  7. fileName = new String(fileName.getBytes("iso8859-1"),"UTF-8");
  8. //上传的文件都是保存在/WEB-INF/upload目录下的子目录当中
  9. String fileSaveRootPath=this.getServletContext().getRealPath("/WEB-INF/upload");
  10. // 处理文件名
  11. String realname = fileName.substring(fileName.indexOf("_")+1);
  12. //通过文件名找出文件的所在目录
  13. String path = findFileSavePathByFileName(fileName,fileSaveRootPath);
  14. //得到要下载的文件
  15. File file = new File(path+File.separator+fileName);
  16. //如果文件不存在
  17. if(!file.exists()){
  18. request.setAttribute("message", "您要下载的资源已被删除!!");
  19. request.getRequestDispatcher("/message.jsp").forward(request, response);
  20. return;
  21. }
  22.  
  23. //设置响应头,控制浏览器下载该文件
  24. response.setHeader("content-disposition", "attachment;filename=" + URLEncoder.encode(realname, "UTF-8"));
  25. //读取要下载的文件,保存到文件输入流
  26. FileInputStream fis = new FileInputStream(path + File.separator + fileName);
  27. //创建输出流
  28. OutputStream fos = response.getOutputStream();
  29. //设置缓存区
  30. ByteBuffer buffer = ByteBuffer.allocate(1024);
  31. //输入通道
  32. FileChannel readChannel = fis.getChannel();
  33. //输出通道
  34. FileChannel writeChannel = ((FileOutputStream)fos).getChannel();
  35. while(true){
  36. buffer.clear();
  37. int len = readChannel.read(buffer);//读入数据
  38. if(len < 0){
  39. break;//传输结束
  40. }
  41. buffer.flip();
  42. writeChannel.write(buffer);//写入数据
  43. }
  44. //关闭输入流
  45. fis.close();
  46. //关闭输出流
  47. fos.close();
  48. }
  49.  
  50. @Override
  51. protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
  52. doPost(request, response);
  53. }
  54. //通过文件名和存储上传文件根目录找出要下载的文件的所在路径
  55. public String findFileSavePathByFileName(String fileName,String fileSaveRootPath){
  56. int hashcode = fileName.hashCode();
  57. int dir1 = hashcode&0xf;
  58. int dir2 = (hashcode&0xf0)>>4;
  59. String dir = fileSaveRootPath + "\\" + dir1 + "\\" + dir2;
  60. File file = new File(dir);
  61. if(!file.exists()){
  62. file.mkdirs();
  63. }
  64. return dir;
  65. }
  66. }

  3、如果IO成为系统的瓶颈,可以考虑使用NIO来实现下载,提供系统性能,改进后的DownloadServlet代码如下:

  1. public class DownLoadServlet1 extends HttpServlet{
  2.  
  3. @Override
  4. protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
  5. //得到要下载的文件名
  6. String fileName = request.getParameter("filename");
  7. fileName = new String(fileName.getBytes("iso8859-1"),"UTF-8");
  8. //上传的文件都是保存在/WEB-INF/upload目录下的子目录当中
  9. String fileSaveRootPath=this.getServletContext().getRealPath("/WEB-INF/upload");
  10. // 处理文件名
  11. String realname = fileName.substring(fileName.indexOf("_")+1);
  12. //通过文件名找出文件的所在目录
  13. String path = findFileSavePathByFileName(fileName,fileSaveRootPath);
  14. //得到要下载的文件
  15. File file = new File(path+File.separator+fileName);
  16. //如果文件不存在
  17. if(!file.exists()){
  18. request.setAttribute("message", "您要下载的资源已被删除!!");
  19. request.getRequestDispatcher("/message.jsp").forward(request, response);
  20. return;
  21. }
  22.  
  23. //设置响应头,控制浏览器下载该文件
  24. response.setHeader("content-disposition", "attachment;filename=" + URLEncoder.encode(realname, "UTF-8"));
  25. //读取要下载的文件,保存到文件输入流
  26. FileInputStream in = new FileInputStream(path + File.separator + fileName);
  27. //创建输出流
  28. OutputStream os = response.getOutputStream();
  29. //设置缓存区
  30. byte[] bytes = new byte[1024];
  31. int len = 0;
  32. while((len = in.read(bytes))>0){
  33. os.write(bytes);
  34. }
  35. //关闭输入流
  36. in.close();
  37. //关闭输出流
  38. os.close();
  39. }
  40.  
  41. @Override
  42. protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
  43. doPost(request, response);
  44. }
  45. //通过文件名和存储上传文件根目录找出要下载的文件的所在路径
  46. public String findFileSavePathByFileName(String fileName,String fileSaveRootPath){
  47. int hashcode = fileName.hashCode();
  48. int dir1 = hashcode&0xf;
  49. int dir2 = (hashcode&0xf0)>>4;
  50. String dir = fileSaveRootPath + "\\" + dir1 + "\\" + dir2;
  51. File file = new File(dir);
  52. if(!file.exists()){
  53. file.mkdirs();
  54. }
  55. return dir;
  56. }
  57. }

  参考博客:http://www.cnblogs.com/xdp-gacl/p/4200090.html

java文件上传和下载的更多相关文章

  1. Java文件上传与下载

    文件上传与下载可谓上网中的常见现象.apache为我们准备了用于文件上传与下载的两个jar包(commons-fileupload-1.2.1.jar,commons-io-1.4.jar).我们在w ...

  2. Java 文件上传与下载、email

    1. 文件上传与下载 1.1 文件上传 文件上传,要点: 前台: 1. 提交方式:post 2. 表单中有文件上传的表单项: <input type="file" /> ...

  3. common-fileupload组件实现java文件上传和下载

    简介:文件上传和下载是java web中常见的操作,文件上传主要是将文件通过IO流传放到服务器的某一个特定的文件夹下,而文件下载则是与文件上传相反,将文件从服务器的特定的文件夹下的文件通过IO流下载到 ...

  4. selenium java 文件上传、下载

    1.webdriver对页面文件的下载 我们一般操作浏览器下载时会让我们选择下载的目录然后经过一系列操作后才进行文件下载操作,但是用webdriver不能按这样的方式操作.经过查询资料找到了如下的实现 ...

  5. java文件上传、下载、图片预览

    多文件保存到本地: @ResponseBody    @RequestMapping(value = "/uploadApp",produces = { "applica ...

  6. 2013第38周日Java文件上传下载收集思考

    2013第38周日Java文件上传&下载收集思考 感觉文件上传及下载操作很常用,之前简单搜集过一些东西,没有及时学习总结,现在基本没啥印象了,今天就再次学习下,记录下自己目前知识背景下对该类问 ...

  7. SpringMVC文件上传和下载的实现

    SpringMVC通过MultipartResolver(多部件解析器)对象实现对文件上传的支持. MultipartResolver是一个接口对象,需要通过它的实现类CommonsMultipart ...

  8. java web学习总结(二十四) -------------------Servlet文件上传和下载的实现

    在Web应用系统开发中,文件上传和下载功能是非常常用的功能,今天来讲一下JavaWeb中的文件上传和下载功能的实现. 对于文件上传,浏览器在上传的过程中是将文件以流的形式提交到服务器端的,如果直接使用 ...

  9. java文件上传下载

    文件上传首先要引入两个核心包 commons-fileupload-1.2.1.jar commons-io-1.4.jar 下面是对文件上传和下载的一些代码做的一个简单封装,可以方便以后直接使用[使 ...

随机推荐

  1. aircack-ng抓握手包

    1.关闭影响进程 airmon-ng check kill 将要进入监听模式的无线网卡断开它已连接的AP 2.查看无线网卡的名字 ifconfig ,例如 wlan0 3.进入监听模式: airmon ...

  2. 原来今天是感恩节-Linux基础继续&MySQL和PHP

    hi 原来今天是感恩节.虽然一直没有过这个节日的习惯,但仅仅是听到感恩的消息,都能想到一幅幅画面.愿大家安好! 下午开题会议还是有所收获,悄悄的,就变向那个不喜欢自己的人了. 一.Linux基础(二) ...

  3. git 学习使用总结三(远程仓库操作)

    这篇文章仅供自己以后翻阅加深记忆,要系统的学习 git 教程(中文版),请移步到 liaoxuefeng.com 学习 git 教程部分. pull, fetch, clone, push, chec ...

  4. 【2016-10-15】【坚持学习】【Day6】【组合模式】

    哈哈,今天偷懒了,在晚上只看了一个组合模式. 例子: 树结构,有一些是树节点,一些是叶子节点. 比如,文件夹树结构,一个是文件夹节点,一个是文件节点,虽然都是树的节点,但是具体的业务肯定是区别的. 代 ...

  5. csu 1812: 三角形和矩形 凸包

    传送门:csu 1812: 三角形和矩形 思路:首先,求出三角形的在矩形区域的顶点,矩形在三角形区域的顶点.然后求出所有的交点.这些点构成一个凸包,求凸包面积就OK了. /************** ...

  6. codeforces118D. Caesar's Legions

    地址:http://www.codeforces.com/problemset/problem/118/D 题目: Gaius Julius Caesar, a famous general, lov ...

  7. notepad++编译并运行java (自定义包)

    最近用Notepad++写汇编,感觉用起来挺顺手,于是想能不能也在这个优秀的编辑器下编写java并编译运行呢,因为每次启动eclipse都要挺长时间,而且eclipse实在太占内存了... 于是各种百 ...

  8. POJ1849Two[DP|树的直径](扩展HDU4003待办)

    Two Time Limit: 1000MS   Memory Limit: 30000K Total Submissions: 1390   Accepted: 701 Description Th ...

  9. instanceof

    java 中的instanceof 运算符是用来在运行时指出对象是否是特定类的一个实例. instanceof通过返回一个布尔值来指出,这个对象是否是这个特定类或者是它的子类的一个实例. result ...

  10. NOI 2002 营业额统计 (splay or fhq treap)

    Description 营业额统计 Tiger最近被公司升任为营业部经理,他上任后接受公司交给的第一项任务便是统计并分析公司成立以来的营业情况. Tiger拿出了公司的账本,账本上记录了公司成立以来每 ...