码迷,mamicode.com
首页 > 编程语言 > 详细

javaWeb系列之十七(上传下载)

时间:2015-06-24 16:35:36      阅读:338      评论:0      收藏:0      [点我收藏+]

标签:



1、文件的上传
    (1)什么是上传:把客户端的文件 上传 到服务器上 。比如云盘
    (2)实现上传:servlet里面没有提供上传的技术。就需要使用第三方组件,实现上传
    (3)实现上传的技术:
    jspSmartUpload:适于嵌入执行上传下载操作的JSP文件中
    针对jsp+javabean模式的,模型一
    fileUpload:mvc的开发模式,模型二
    FileUpload 是 Apache commons下面的一个子项目,用来实现Java环境下面的文件上传功能
    组件FileUpload依赖于Commons IO组件
    实现上传使用的第三方的技术,首先需要导入jar包
    (4)如何实现上传(要求):
    第一个要求:有表单,但是method必须是post
    第二个要求:必须要有文件输入项,在文件输入项里面必须要name属性 <input type="file" name="file"/>
    第三个要求:在表单里面 enctype :multipart/form-data
    enctype默认值:application/x-www-form-urlencoded
    (5)文件上传的实现过程(画图)
   
(6)使用代码实现文件的上传
    导入fileupload的jar包
    使用到类 DiskFileItemFactory:磁盘文件项工厂
    ServletFileUpload:核心上传类
    FileItem:文件项
    步骤(固定)
    1、创建磁盘文件项工厂  new  DiskFileItemFactory()
    2、创建核心的上传类    new ServletFileUpload(FileItemFactory fileItemFactory)
    3、使用核心上传类解析request对象  parseRequest(javax.servlet.http.HttpServletRequest request)
    返回list集合 泛型 FileItem
    4、遍历list集合
    5、判断FileItem是普通项还是文件上传项
    如果是一个普通项,得到普通项的名称和值
    如果是文件上传项,实现文件上传的代码

(7)核心api的使用
    DiskFileItemFactory:磁盘文件项工厂
    构造方法
    DiskFileItemFactory()
    有两个方法设置
    setSizeThreshold(int sizeThreshold)
    setRepository(java.io.File repository)
    DiskFileItemFactory(int sizeThreshold, java.io.File repository)
    第一个参数:缓冲区的大小 10k ;
    第二个参数:临时文件存储路径,上传的文件大小超过缓冲区的大小产生临时文件

    ServletFileUpload:核心上传类
    构造方法 ServletFileUpload(FileItemFactory fileItemFactory)
    解析request对象:parseRequest(javax.servlet.http.HttpServletRequest request)
    返回list集合,泛型FileItem

    设置文件名称有中文,设置编码:setHeaderEncoding(java.lang.String encoding)
    设置单个文件上传的大小:setFileSizeMax(long fileSizeMax)
    设置所有文件上传的总的大小:setSizeMax(long sizeMax)
    FileItem接口:文件项
    isFormField():判断是普通项还是文件项 true和false,如果true表示普通项,如果false表示文件上传项
    getFieldName():获取普通项的name的名称
    getString():获取普通项输入的值
    getString(java.lang.String encoding):设置编码
    getName():获取上传文件名称(加路径)
    在某些浏览器里面,得到只是文件名称 没有路径 1.txt
    getInputStream() :得到提交文件的输入流
    delete():删除临时文件

    (8)练习:js控制多文件的上传
    有两个按钮:上传和增加
    当点击增加,增加一个文件上传项和删除按钮
    单点击删除,把删除按钮所在的那一行删除
    点击上传,把页面上所有的文件上传到服务器
    js代码
  //增加方法
    function add1() {
    //得到div
    var divv = document.getElementById("divv");
    //向div里面写html代码
    divv.innerHTML += "<div><input type=‘file‘ name=‘file1‘ /> <input type=‘button‘ value=‘del‘ onclick=‘del1(this);‘/></div>";
}

    //删除操作
    function del1(who) {
    //得到del按钮的所在的div
    var div = who.parentNode;
    //删除div
    var divv = div.parentNode;
    divv.removeChild(div); 
    }
    (9)上传的问题解决
    文件的重名的问题
    如果多次上传相同的文件名称的文件,最后一次上传的文件会把之前文件覆盖
    解决方式:
    在文件名称后面加一个随机的字符串  abbcdfdfer_1.txt
    得到随机的字符串: uuid得到唯一的字符串
    //得到唯一的字符串 使用uuid
    String uuid = UUID.randomUUID().toString();
    //在文件之前添加uuid的值  uuid_filename
    filename = uuid+"_"+filename;

    上传的所有的文件都会放到一个文件夹里面,如果文件很多,读写很慢
    在企业级开发中
    根据时间进行分离: 根据年  月  天 
    根据用户进行分离:比如张三上传文件存到张三
    根据文件数量进行分离:每3000个文件存到一个文件夹
    使用目录分离的算法实现   
    首先得到文件的唯一的文件名
    根据这个唯一的文件名.hashcode()操作,得到唯一的int值
    使用得到的唯一的值,& 0xf 把结果作为第一级目录
    使用int值,右移四位,再& 0xf,把结果作为第二级目录
    int 32位,在计算机里面如何表示?
    每四位表示一段 ,8段 

2、文件的下载
    (1)文件下载几种方式:两种
    直接使用超链接实现 <a href="文件路径"></a>
    这种方式不好,图片格式直接打开,而zip格式才会提示下载
    写代码实现下载
    步骤
    //创建磁盘文件项工厂
   DiskFileItemFactory factory = new DiskFileItemFactory();
   //创建核心上传类
   ServletFileUpload upload = new ServletFileUpload(factory);
   upload.setHeaderEncoding("utf-8");
   //解析request对象
   List<FileItem> list = upload.parseRequest(request);
   //创建Resource对象
   Resource res = new Resource();
   //遍历list集合
   for (FileItem fileItem : list) {
    //判断是否普通输入项
    if(fileItem.isFormField()) {
     String des = fileItem.getString("utf-8");
     System.out.println(des);
     res.setDes(des);
    } else {//文件上传项
     //得到上传文件名称  c:\a\a.txt
     String filename = fileItem.getName();
     int lens = filename.lastIndexOf("\\");
     if(lens != -1) {
      filename = filename.substring(lens+1);
     }
     //得到随机的字符串
     String uuid = UUID.randomUUID().toString();
     String uuidname = uuid+"_"+filename;
    
     //得到上传文件夹的完全路径
     String path = getServletContext().getRealPath("/uploadfile");
    
     //得到分离之后的路径
     String url = UploadUtils.getPath1(uuidname);
     //判断文件夹是否存在,如果不存在,需要创建
     File file = new File(path+url);
     if(!file.exists()) {
      file.mkdirs();
     }
     //得到上传文件
     InputStream in = fileItem.getInputStream();
     //使用输出流把文件写到文件夹里面
     OutputStream out = new FileOutputStream(path+url+"/"+uuidname);
     //流对接
     int len = 0;
     byte[] b = new byte[1024];
     while((len=in.read(b))!=-1) {
      out.write(b, 0, len);
     }
     //关闭流
     in.close();
     out.close();
    
     //设置上传的信息
     res.setUuidname(uuidname);
     res.setRealname(filename);
     res.setSavepath(path+url);
(2)代码实现文件的下载   
    //得到要下载文件的路径
    String path = request.getParameter("filename");
    path = new String(path.getBytes("iso8859-1"),"utf-8");
    //  System.out.println("path::  "+path); c:\1\a.mp3
    //得到文件名称
    String filename = path.substring(path.lastIndexOf("\\")+1);
    //处理不同的浏览器中文问题
    //解决中文乱码问题
    //得到当前请求的浏览器的类型
    String agent = request.getHeader("User-Agent");
 
  //如果是火狐浏览器
    if(agent.contains("Firefox")) {
    //base64编码
    filename = "=?UTF-8?B?"+
           new BASE64Encoder().encode(filename.getBytes("utf-8"))+"?=";
    } else {//ie浏览器
    filename = URLEncoder.encode(filename, "utf-8");
    }
    //设置mime类型
    String type = getServletContext().getMimeType(filename);
    response.setContentType(type);
    //设置头信息 
    response.setHeader("Content-Disposition", "attachment;filename="+filename);
    //得到要下载文件的输入流
    InputStream in = new FileInputStream(path);
    //使用输出流把写到浏览器
    OutputStream out = response.getOutputStream();
    int len = 0;
    byte[] b = new byte[1024];
    while((len=in.read(b))!=-1) {
    out.write(b, 0, len);
    }
    in.close();
(3)练习:给定任意的一个目录,把目录里面的所有的文件都显示出来(无论有多少层)
    实现思路:
    使用到树
    树的遍历:深度优先遍历和广度优先遍历
    可以使用队列实现树的遍历,队列特点是FIFO,先进先出
    1、创建队列
    - Queue<File> que = new LinkedList<File>();
    - 入队:offer(E e)
    - 出队:poll()
<%
     //创建文件
     File root = new File("f:\\1");
     //创建队列
     Queue<File> qu = new LinkedList<File>();
     //把根节点入队
     qu.offer(root);
     //判断如果队列不为空
     while(!qu.isEmpty()) {
      //把根节点出队
      File file = qu.poll();
      //得到所有的文件和文件夹
      File[] files = file.listFiles();
      //遍历
      for(File f : files) {
       //判断是否是文件,如果是文件直接显示,不是文件继续入队
       if(f.isFile()) {
    %>
      <a href="/day20/downlist?filename=<%=f.getCanonicalPath()%>"><%=f.getName() %></a> <br/>
    <%
       } else {//不是文件
        //入队
        qu.offer(f);
       }
      }
     }
     %>
    2、把根节点入队,再把根节点出队
    3、根节点出队之后,可以得到根节点的子节点
    4、把子节点入队,在出队,获得子节点的子节点
    依次类推....
    实现文件的下载
 
  //对文件名进行hashcode操作,返回int类型
  int code1 = filename.hashCode();
  //使用int值 & oxf
  int d1 = code1 & 0xf;
  //int值右移四位
  int code2 = code1 >>> 4;
  //把code2再&0xf
  int d2 = code2 & 0xf;
  return "/"+d1+"/"+d2;
 }













javaWeb系列之十七(上传下载)

标签:

原文地址:http://blog.csdn.net/lois_yue/article/details/46621323

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!