zoukankan      html  css  js  c++  java
  • 文件上传下载总结

    文件下载的步骤:

    jsp省略;

    servlet代码:

     1 public class DownServlet extends HttpServlet{
     2 
     3         @Override
     4         protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
     5             req.setCharacterEncoding("utf-8");
     6             resp.setContentType("text/html;charset=utf-8");
     7             
     8             //获取文件名
     9             String fileName = req.getParameter("fileName");
    10             //获取文件的具体位置
    11             String realPath = this.getServletContext().getRealPath("down");
    12             
    13             File file =new File(realPath+"/"+fileName);
    14             //创建输入流
    15             InputStream is= new FileInputStream(file);
    16             //设置响应头
    17             resp.setHeader("content-disposition", "attachment;filename=" + URLEncoder.encode(fileName, "utf-8"));
    18             //创建输出流
    19             //OutputStream os=new FileOutputStream();
    20             ServletOutputStream os = resp.getOutputStream();
    21             //声明一次读取大小
    22             int len=0;
    23             //中间容器
    24             byte [] buffer= new byte[200];
    25             //循环读取
    26             while((len=is.read(buffer))!=-1){
    27                 os.write(buffer, 0, len);
    28             }
    29             os.flush();
    30             os.close();     
    31         }
    32 }

    文件上传:

    主要代码:

     1 public class UploadServlet extends HttpServlet {
     2     @Override
     3     protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
     4         req.setCharacterEncoding("utf-8");
     5         resp.setContentType("text/html;charset=utf-8");
     6         UserDao dao = new UserDao();
     7         User user = new User();
     8         InputStream is = null;
     9         OutputStream os = null;
    10         try {
    11             // 获取工厂类
    12             DiskFileItemFactory factory = new DiskFileItemFactory();
    13             // 获取对象
    14             ServletFileUpload fileUpload = new ServletFileUpload(factory);
    15             List<FileItem> fileItemList = fileUpload.parseRequest(req);
    16             // 遍历文件条目fileItem
    17             for (FileItem fileItem : fileItemList) {
    18                 if (fileItem.isFormField()) {// type:普通文本
    19                     if ("username".equals(fileItem.getFieldName())) {
    20                         // String username = fileItem.getFieldName();
    21                         user.setUsername(fileItem.getString("UTF-8"));
    22                     }
    23                     if ("birth".equals(fileItem.getFieldName())) {
    24                         // String username = fileItem.getFieldName();
    25                         user.setBirth(DateUtil.stringParserDate(fileItem.getString()));
    26                     }
    27                     if ("addr".equals(fileItem.getFieldName())) {
    28                         // String username = fileItem.getFieldName();
    29                         user.setAddr(fileItem.getString("utf-8"));
    30                     }
    31                 } else {
    32                     // type:file
    33                     // 获取文件上传目的地的 路径
    34                     String realPath = this.getServletContext().getRealPath("upload");
    35                     System.out.println(realPath);
    36                     // 获取 文件名
    37                     String fieldName = fileItem.getName();
    38                     if (fieldName != null) {
    39                         user.setPhoto(realPath + "/" + fieldName);
    40                     }
    41                     // 获取输入流
    42                     is = fileItem.getInputStream();
    43                     // 创建输出流
    44                     File f = new File(realPath + "/" + fieldName);
    45                     os = new FileOutputStream(f);
    46                     // 声明一次读取大小
    47                     int len = 0;
    48                     // 中间容器
    49                     byte[] buffer = new byte[200];
    50                     // 循环读取
    51                     while ((len = is.read(buffer)) != -1) {
    52                         os.write(buffer, 0, len);
    53                     }
    54                 }
    55             }
    56         } catch (FileUploadException e) {
    57             e.printStackTrace();
    58         } finally {
    59             os.flush();
    60             os.close();
    61             is.close();
    62         }
    63         boolean flag = dao.addUser(user);
    64         if (flag) {
    65             req.getRequestDispatcher("index.jsp").forward(req, resp);
    66         }
    67     }
    68 }

    文件条目:FileItem类总结:

    FileItem类的常用方法

          1.boolean  isFormField():isFormField方法用来判断FileItem对象里面封装的数据是一个普通文本表单字段,还是一个文件表单字段。如果是普通文本表单字段,返回一个true否则返回一个false。因此可以用该方法判断是否是普通表单域还是文件上传表单域。

          2.String getName():getName方法用来获得文件上传字段中的文件名。

          3.String getFieldName():getFieldName方法用来返回表单标签的name属性的值。

          4.void write(File file):write方法将FileItem对象中的内容保存到某个指定的文件中。如果FileItem对象中的内容是保存在某个临时文件中,该方法完成后,临时文件可以会被删除。该方法也可以将普通表单字段保存在一个文件中,但最主要的用途是把上传的文件内容保存在本地文件系统中。

          5.String getString():getString(“utf-8”)(在获取普通文本内容时容易乱码)方法将FileItem对象中保存的数据流内容以一个字符串返回。它有两个重载形式。public Java.lang.String getString()和public java.lang.String getString(java.lang.String encodeing) throws java.io.UnsupportedEncodingException。前者使用缺省的字符集编码将主体内容转换成字符串,后者使用参数指定的字符集编码。如果在读取普通表单字段元素的内容时,出现了乱码现象,可以调用第二个方法,并传入 正确的字符集编码名称。

          6.String getContentType():此方法用来获得上传文件的类型,即标段字段元素描述头属性“content-type”的值,如image/jpeg。如果FileItem对象对应的是普通的表单字段,将返回null。

          7.boolean isInMemory():判断FileItem对象封装的数据是保存在内存中还是硬盘中。

          8.void  delete():此方法用来清空FileItem对象中封装的主体内容,如果内容是被保存在临时文件中,该方法会把临时文件删除。

          9.InputStream  getInputStream()。以流的形式返回上传文件的主体内容。

          10.long  getSize():返回上传文件的大小。

    转一篇fileupload详细总结:

    前台页面不用多说  主要是form表单中设置 enctype="multipart/form-data" 很重要。

     

    处理上传jsp文件

          
       判断表单是否是Multipart类型的。这里可以直接对request进行判断
        if (ServletFileUpload.isMultipartContent(request)) {
        // 创建文件处理工厂,它用于生成 FileItem 对象。 
        DiskFileItemFactory factory = new DiskFileItemFactory(); 
         设置文件的缓存路径
           String tempdir =this.getServletContext().getRealPath("/upload/temp");    
         Java.io.File d = new java.io.File(savedir);
            if(!d.exists()){
             d.mkdirs();
            }
         
        factory.setSizeThreshold(1024*1024); // 设置最多只允许在内存中存储的数据,单位:字节
        factory.setRepository(d); // 设置一旦文件大小超过getSizeThreshold()的值时数据存放在硬盘的目录(默认可以不用设置)

        // Create a new file upload handler
        ServletFileUpload upload = new ServletFileUpload(factory);
        // 设置允许用户上传文件大小,单位:字节
        upload.setSizeMax(yourMaxRequestSize);
        //上传文件,并解析出所有的表单字段,包括普通字段和文件字段
        List  items = upload.parseRequest(request); 
             //下面对每个字段进行处理,分普通字段和文件字段
       Iterator it = items.iterator();
       while(it.hasNext()){
        FileItem fileItem = (FileItem) it.next();
        //如果是普通字段
        if(fileItem.isFormField()){  //是普通的字段
         System.out.println(fileItem.getFieldName() + "   " + fileItem.getName() + "   " + new String(fileItem.getString().getBytes("iso8859-1"), "gbk"));
        fileItem.getFieldName();//得到字段name属性的值
        fileItem.getName();//得到file字段的文件名全路径名,如果不是file字段,为null
        fileItem.getString();//得到该字段的值,默认的编码格式
        fileItem.getString("UTF-8");//指定编码格式
        }else{//文件字段
             System.out.println(fileItem.getFieldName() + "   " +
            fileItem.getName() + "   " +//得到file字段的文件名全路径名
            fileItem.isInMemory() + "    " +//用来判断FileItem类对象封装的主体内容是存储在内存中,还是存储在临时文件中,如果存储在内存中则返回true,否则返回false
            fileItem.getContentType() + "   " +//文件类型
            fileItem.getSize());          //文件大小

           //什么东西都有了 ,想怎么处理都可以了
         //保存文件,其实就是把缓存里的数据写到目标路径下
         if(fileItem.getName()!=null && fileItem.getSize()!=0){
          File fullFile = new File(fileItem.getName());
          File newFile = new File("c:/temp/" + fullFile.getName());
          try {
           fileItem.write(newFile);
          } catch (Exception e) {
           e.printStackTrace();
          }
         }else{
          System.out.println("文件没有选择 或 文件内容为空");
         }

     

     

    一、文件上传入门

    1. 应用:

     用户上传头像、上传图片、邮件上传附件等

    2. 页面表单的实现

        文件上传表单和普通表单有两个区别

        1) 需要文件上传字段  <input type=”file” />

        2) form 表单的 enctype 属性需要指定为 multipart/form-data

    3. 服务器端解析request

        在 Servlet 中通过 request.getInputStream 获得表单上传数据,会发现数据是分段发送的

    由于自己写程序解析有难度,我们可以使用Apache 开发的开源组件Commons-fileupload

    需要导入 jar 包Commons-fileupload 和Commons-io

    4 . UploadServlet 中处理文件上传程序

    // 1. 创建工厂类

    DiskFileItemFactory factory = new DiskFileItemFactory();

    // 2. 创建FileUpload对象

    ServletFileUpload upload = new ServletFileUpload(factory);

    // 3. 判断是否是上传表单

    boolean b = upload.isMultipartContent(request);

    if(!b) {

        // 不是文件上传

    request.setAttribute("message", "对不起,不是文件上传表单!");

    request.getRequestDispatcher("/message.jsp").forward(request, response);

        return;

    }

    // 是文件上传表单

    // 4. 解析request,获得FileItem项

    List<FileItem> fileitems = upload.parseRequest(request);

    // 5. 遍历集合

    for(FileItem item : fileitems) {

        // 判断是不是普通字段

    if(item.isFormField()) {

        String name = item.getFieldName();

        String value = item.getString();

        // 手工的转换了

        value = new String(value.getBytes("iso-8859-1"),"utf-8");

        System.out.println(name + "=" + value);

    } else {

        // 文件上传字段

        // 获得文件名

        String filename = item.getName();

        System.out.println(filename);

        filename = filename.substring(filename.lastIndexOf("\")+1);

       

        System.out.println(filename);

        // 创建文件

        ServletContext context = getServletContext();

        String dir = context.getRealPath("WEN-INF/upload");

        File file = new File(dir, filename);

        file.createNewFile();

       

        // 获得流,读取数据写入文件

        InputStream in = item.getInputStream();

        FileOutputStream fos = new FileOutputStream(file);

       

        int len;

        byte[] buffer = new byte[1024];

        while((len=in.read(buffer))>0)

           fos.write(buffer,0,len);

        fos.close();

        in.close();

        item.delete();    // 删除临时文件

    }

     

     

    二、 文件上传处理细节

    1. 中文乱码问题

        1) 文件名中文乱码问题,解决办法: 告诉文件上传组件以什么编码方式来解码文件名

           ServletUpload.setCharacterEncoding(“utf-8”);

           request. setCharacterEncoding(“utf-8”);

        

        2) 普通字段中文乱码问题

           fileitem.getString(“utf-8”);      

     

    2.   临时文件

        对于大文件不能缓存在内存,需要缓存到硬盘,为了方便管理,我们需要设置临时文件存放目录

        // 设置临时文件的存放位置

    factory.setRepository(new File("d:/temp"));

     

        文件上传完毕需要删除临时文件,否则会导致服务器存在两份上传文件

    // 注意,需要先将流进行关闭,否则会导致临时文件无法删除

    out.close();

    in.close();

    // 删除临时文件

    fileitem.delete();

     

    3. 文件存放目录

        1) 目录需要隐藏,禁止外界直接访问

        2) 文件名需要保证不重复

        3) 文件应该分目录存放

     

    三、上传进度条

    1. 实现进度监听

        需要实现对文件上传进度的监听,需要给FileUpload 对象添加 ProgressListener

        在upload方法中对与进度相关的数据进行处理

        upload.setProgressListener(new ProgressListener() {

        long num = 0;

        public void update(long bytesRead, long contentLength, int items) {

          

                long progress = bytesRead*100/contentLength;

               if(progress==num)

                   return;

               num = progress;

               System.out.println("上传进度:" + progress + "%");

          

            //  request.getSession().setAttribute("progress", progress);

            }

        });

     

    2. 在 jsp 页面显示进度

        实验: 

        1) 使用 iframe 发送请求, 请求一个Servlet, 在Servlet 中返回响应,发送自增的num

           此时会发现 iframe 会不停第想Servlet发送请求

        2) 点击文件上传按钮后,iframe立刻停止刷新,直至上传完毕页面跳转至新页面

        3)为了观察实验结果,将form 的 target 指定为 iframe, UploadServlet回送上传完毕的结果

        4) 出现上述问题的原因,浏览器不支持多线程同时访问服务器只能同时发送一个请求,

           这样的访问方式为同步访问

        5) 要在文件上传的同时在iframe中实现进度访问,就需要ie浏览器与服务器进行异步交互

           此时就需要 XMLHttpRequest 对象

           在JavaScript中可以直接使用XMLHttpRequest 对象与服务器进行异步通信

           获得XmlHttpRequest 对象的方式有两种

           ie7以上版本

           var xhr = null;

           if(window.XMLHttpRequest)

               xhr = new XMLHttpRequest();

           ie7以下版本

           if(window.ActiveXObject)

               xhr = new ActiveXObject(“Microsoft.XMLHTTP”);

          

           获得对象后需要调用open方法输入请求地址

           注意请求方式, 地址的输入, 并且需要设置为true 指定异步访问该地址

           xhr.open(“get”,”/upload/servlet/UploadServlet”, false)

          

           // 调用send 方法发送请求,post方式需要发送消息体,get方式则不用直接传入null值

           xhr.send(null);

          

           // 访问 responseText 属性获得 Servlet 回送的数据

           document.write(xhr.responseText);

     

    四、 api方法

    1. DiskFileItemFactory 对象

        设置缓冲区大小,字节为单位,默认为10K,一般不用修改

        factory.setSizeThreshold(1000);

        设置临时文件存放目录

        factory.setRepository(file);

     

    2. ServletFileUpload 对象

        判断是否为文件上传表单

        boolean b = upload.isMultipartContent(request);

       解析request对象

       List<FileItem> list = upload.parseRequest(request);

       设置上传文件的最大值

        setFileSizeMax(long fileSizeMax)

        设置上传文件总量的最大值

        setSizeMax(long sizeMax)

        设置编码格式

        setHeaderEncoding(java.lang.String encoding)

        注册进度监听器

        setProgressListener(ProgressListener pListener)

     

    3. FileItem 对象

        获得表单字段的属性名

        item.getFieldName();

        获得普通字段的值

        item.getString(charsetName)

        获得文件上传字段的文件名

        item.getName()

        获得文件上传的流

        item.getInputStream()

    public class DownServlet extends HttpServlet{
    @Overrideprotected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {req.setCharacterEncoding("utf-8");resp.setContentType("text/html;charset=utf-8");//获取文件名String fileName = req.getParameter("fileName");//获取文件的具体位置String realPath = this.getServletContext().getRealPath("down");File file =new File(realPath+"/"+fileName);//创建输入流InputStream is= new FileInputStream(file);//设置响应头resp.setHeader("content-disposition", "attachment;filename=" + URLEncoder.encode(fileName, "utf-8"));//创建输出流//OutputStream os=new FileOutputStream();ServletOutputStream os = resp.getOutputStream();//声明一次读取大小int len=0;//中间容器byte [] buffer= new byte[200];//循环读取while((len=is.read(buffer))!=-1){os.write(buffer, 0, len);}os.flush();os.close(); }}

  • 相关阅读:
    非常牛的实现三个数交换
    assert后面如果是假则程序崩溃
    python三元操作符
    三种方法划分成绩等级
    爱因斯坦难题
    打印奇数
    判断给到的年份是否为闰年
    【bzoj1895】Pku3580 supermemo Splay
    【bzoj1050】[HAOI2006]旅行comf 并查集
    【bzoj4002】[JLOI2015]有意义的字符串 数论+矩阵乘法
  • 原文地址:https://www.cnblogs.com/wym789/p/6323194.html
Copyright © 2011-2022 走看看