文件上傳和下載

文件上傳的概述(上傳不能使用BaseServlet)

1.上傳對錶單限制

  * method="post"html

  * enctype="multipart/form-data"若是不加這個,它會把體中的中文生成url編碼的形式;上傳的時候用它java

  * 表單中須要添加文件表單項:<input type="file" name="xxx" ...>web

2.上傳對Servlet限制

  * request.getParameter("xxx");這個方法在表單爲enctype="multipart/form-data"時,它做廢了。它永遠返回null。apache

  * ServletInputStream  request.getInputStream();包含整個請求的體!數組

---------------------------------------------------------------------瀏覽器

3.多部件表單的體

1.每隔出多個部件,即一個表單項一個部件緩存

2.一個部件中本身包含請求頭和空行,以及請求體。服務器

3普通表單項:jsp

  > 一個頭:Content-Disposition:包含name="xxx",即表單項名稱。post

  > 體就是表單項的值。

4.文件表單項:

  > 兩個頭:

    * Content-Disposition:包含name="xxx",即表單項名稱;還有一個filename="yyy.jpg",表示上傳文件的名稱。

    * Content-Type:它是上傳文件的MIME類型,例如image/pjpeg,表示上傳的是圖片,圖中是jpg擴展名的圖片。

  > 體就是上傳文件的內容。

------WebKitFormBoundary6opWGr8NaACK9My4
Content-Disposition: form-data; name="username"

taeyeon
------WebKitFormBoundary6opWGr8NaACK9My4
Content-Disposition: form-data; name="zhaoPian"; filename="lovejrr.jpg"
Content-Type: image/jpeg

文件內容
------WebKitFormBoundary6opWGr8NaACK9My4--

4.commons-fileupload

commons-fileupload-1.2.2.jar------這個小組件,它會幫咱們解析request中上傳的數據,解析後的結果是一個表單項數據封裝到一個FileItem對象中。咱們只須要調用FileItem的方法便可!

commons-io.jar-----依賴

1)上傳三步

  相關類:

    * 工廠:DiskFileItemFactory

    * 解析器:ServletFileUpload

    * 表單項:FileItem

a)建立工廠:DiskFileItemFactory  factory  =  new  DiskFileItemFactory();

b)建立解析器:ServletFileUpload  sfu = new ServletFileUpload(factory);

c)使用解析器來解析request,獲得FileItem集合:List<FileItem>   fileItemList = sfu.parseRequest(request);

2)FileItem---(一個接口,它有實現類)

  * boolean  isFormField():是否爲普通表單項!返回true爲普通表單項,若是返回false即文件表單項!

  * String getFieldName():返回表單項的名稱;

  * String getString(String charset):返回表單項的值;

  * String getName():返回上傳的文件名稱;

  * long getSize():返回上傳文件的字節數;

  * InputStream  getInputStream():返回上傳文件對應的輸入流;

  * void write(File destFile):把上傳的文件內容保存到指定的文件中。

  * String getContentType():返回上傳文件的類型。若是是普通表單,返回的是null。

form2.jsp:

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>


  <body>
    <h1>上傳2</h1>
    <form action='<c:url value="/Upload2Servlet"></c:url>' method="post" enctype="multipart/form-data">
        用戶名:<input type="text" name="username"/><br>
        照片:<input type="file" name="zhaoPian"><br>
        <input type="submit" value="上傳">
    </form>
  </body>

Upload2Servlet.java:

package day22_1;

import java.io.File;
import java.io.IOException;
import java.util.List;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;

public class Upload2Servlet extends HttpServlet {

    public void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        /*
         * 上傳三步
         * 1.建立工廠
         * 2.經過工廠建立解析器
         * 3.解析request,獲得FileItem集合
         * 4.遍歷FileItem集合,調用 其API完成文件的保存
         */
        DiskFileItemFactory factory=new DiskFileItemFactory();
        ServletFileUpload sfu=new ServletFileUpload(factory);
        try {
            List<FileItem> fileItemList = sfu.parseRequest(request);
            FileItem fi1=fileItemList.get(0);
            FileItem fi2=fileItemList.get(1);
            
            System.out.println("普通表單項演示:"+fi1.getFieldName()+"="+fi1.getString("UTF-8"));
            
            System.out.println("Content-Type:"+fi2.getContentType());
            System.out.println("Size:"+fi2.getSize());
            System.out.println("filename:"+fi2.getName());
            
            //保存文件
            File destFile=new File("F:/jrrlove.jpg");
            try {
                fi2.write(destFile);
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        } catch (FileUploadException e) {
            throw new RuntimeException(e);//異常轉換一下
        }
    }
}

 

5.上傳的細節

1)文件必須保存到WEB-INF下!

  * 目的是不讓瀏覽器直接訪問到!

  * 把文件保存到WEB-INF目錄下!

 

2)文件名稱相關問題

  * 有的瀏覽器上傳的文件名是絕對路徑,這須要切割!C:\files\baibing.jpg

    

String filename=fi2.getName();//獲取文件名(有可能帶路徑)
int  index=filename.lastIndexOf("\\");
if(index  !=  -1){
 filename=filename.substring(index+1);
}

  

  * 文件名亂碼或者普通表單項亂碼:request.setCharacterEncoding("utf-8");由於fileupload內部會調用reque.getCharacterEncoding();//優先級低

  fileUpload.setHeaderEncoding(String):這種方式的優先級高於前一種。

  上傳文件內容中包含中文:

    一般咱們不關心上傳文件的內容,由於是把文件保存到硬盤上!若是在控制檯顯示上傳的文件內容,那麼可使用fileItem.getString("utf-8")來處理編碼。

文本文件內容和普通表單項內容使用FileItem類的getString("utf-8")來處理編碼。

  * 文件同名問題:咱們須要爲每一個文件添加名稱前綴,這個前綴要保證不能重複。uuid

    > filename  =  CommonsUtils.uuid() +  "_"  +  filename;

3)目錄打散問題

  * 不能在一個目錄下存放過多文件。

    > 首字母打散:使用文件的首字母作爲目錄名稱,例如:abc.txt,那麼咱們把文件保存到a目錄下。若是a目錄不存在,那麼建立它。

    > 時間打散:使用當前日期作爲目錄。

    > 哈希打散:

      # 經過文件名稱獲得int值,即調用hashCode()

      # 它int 值轉換成16進制0~9,A~F

      #  獲取16進制的前兩位用來生成目錄,目錄爲兩層!例如:1B2C3D4E5F,/1/B/保存文件。

jar包:commons-fileupload.jar

   commons-io.jar

   commons-beanutils.jar

   commons-logging.jar

   itcast-tools.jar

form3.jsp:

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>


<body>
    <h1>上傳3</h1>
    <form action='<c:url value="/Upload3Servlet"></c:url>' method="post"
        enctype="multipart/form-data">
        用戶名:<input type="text" name="username" /><br> 照片:<input
            type="file" name="zhaoPian"><br> <input type="submit"
            value="上傳">
    </form>
</body>

Upload3Servlet.java:

package day22_1;

import java.io.File;
import java.io.IOException;
import java.util.List;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;

import cn.itcast.commons.CommonUtils;

public class Upload3Servlet extends HttpServlet {

    public void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        /*
         * 上傳三步
         */
        //工廠
        DiskFileItemFactory factory=new DiskFileItemFactory();
        //解析器
        ServletFileUpload sfu=new ServletFileUpload(factory);
        //解析,獲得List
        try {
            List<FileItem> list = sfu.parseRequest(request);
            FileItem fi=list.get(1);//獲取文件表單項
            //////////////////////////////////////
            
            /*
             * 1.獲得文件保存的路徑
             */
            String root = request.getServletContext().getRealPath("/WEB-INF/files");
            /*
             * 2.生成兩層目錄
             *     1)獲得文件名稱
             *     2)獲得hashCode
             *     3)轉換成16進制
             *     4)獲取前兩個字符用來生成目錄
             */
            String filename = fi.getName();//獲取上傳的文件名稱
            /*
             * 處理文件名絕對路徑問題
             */
            int index = filename.lastIndexOf("\\");
            if(index != -1){
                filename=filename.substring(index+1);
            }
            /*
             * 給文件名稱加uuid前綴,處理文件同名問題---itcast-tools.jar
             */
            String savename=CommonUtils.uuid()+"_"+filename;
            /*
             * 1.獲得hashCode
             */
            int hCode=filename.hashCode();
            String hex = Integer.toHexString(hCode);
            /*
             * 2獲取hex的前兩個字母,與root鏈接在一塊兒,生成一個完整路徑
             */
            File dirFile=new File(root,hex.charAt(0)+"/"+hex.charAt(1));
            /*
             * 3.建立目錄鏈
             */
            dirFile.mkdirs();
            /*
             * 4.建立目錄文件
             */
            File destFile=new File(dirFile,savename);
            /*
             * 5.保存
             */
            fi.write(destFile);
            
            //////////////////////////////////////            
            
        } catch (FileUploadException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}

在WEB-INF下建一個files目錄,上傳的圖片都會保存到服務器的這個項目下的這files目錄下。

4)上傳文件的大小限制

  * 單個文件大小限制

    > sfu.setFileSizeMax(100*1024):限制單個文件大小爲100KB

    > 上面的方法調用,必須在解析開始以前調用!

    > 若是上傳的文件超出限制,在parseRequest()方法執行時,會拋出異常!FileUploadBase.FileSizeLimitExceedeException。

舉例:-----單個文件大小限制

sfu.setFileSizeMax(100*1024);


catch (FileUploadException e) {
            if(e instanceof FileUploadBase.FileSizeLimitExceededException){
                request.setAttribute("msg", "您上傳的文件超出了100KB!");
                request.getRequestDispatcher("/form3.jsp").forward(request, response);
            }

 

  * 整個請求全部數據大小限制

    > sfu.setSizeMax(1024*1024);//限制整個表單大小爲1M

    > 這個方法也必須在parseRequest()方法以前調用!

    > 若是上傳的文件超出限制,在parseRequest()方法執行時,會拋出異常!FileUploadBase.SizeLimitExceedeException。

5)緩存大小與臨時目錄

上傳的過程:客戶端--->服務器內存--->再到硬盤,因此對應特別大的文件須要使用到緩存一次一次的從內存向硬盤保存數據)。

   * 緩存大小:超出多大,才向硬盤上保存!默認爲10KB。

  * 臨時目錄:向硬盤的什麼目錄保存。

 設置緩存大小與臨時目錄:new DiskFileItemFactory(20*1024,  new File("F:/temp"))

 

        //工廠-----參數:1緩存大小   2臨時目錄
        DiskFileItemFactory factory=new DiskFileItemFactory(20*1024,new File("F:/f/temp"));

*******上傳的文件臨時存放到這個目錄下,等上傳完畢,就會複製到files目錄下,而後該臨時目錄下的文件消失******

6.下載 

1)下載就是向客戶端響應字節數據!

  原來咱們響應的都是html的字符數據!

  把一個文件變成字節數組,使用response.getOutputStream()來響應給瀏覽器!!!

2)下載的要求

  * 兩個頭一個流!

    > Content-Type:你傳遞給客戶端的文件是什麼MIME類型,例如:image/pjpeg

      經過文件名稱調用ServletContext的getMimeType()方法,獲得MIME類型!

    > Content-Disposition:它的默認值爲inline,表示在瀏覽器窗口中打開!attachment;filename=xxx

      在filename=後面跟隨的是顯示在下載框中的文件名稱!

    > 流:要下載的文件數據!

      本身new一個輸入流便可!

示例:

package com.xjs.web.servlet;

import java.io.FileInputStream;
import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.io.IOUtils;

public class Download1Servlet extends HttpServlet {

    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        /*
         * 兩個頭一個流
         * 1.Content-Type
         * 2.Content-Disposition
         * 3.流  下載文件的數據
         */
        String filename="G:/GD.mp3";
        //經過ServletContent的getMimeTypeZ()方法獲得文件的MIME類型
        String contentType = this.getServletContext().getMimeType(filename);
        
        String contentDisposition="attachment;filename=jrr.mp3";
        
        FileInputStream in=new FileInputStream(filename);
        
        //設置頭
        response.setHeader("Content-Type", contentType);
        response.setHeader("Content-Disposition", contentDisposition);
        
        //獲取綁定響應客戶端的流
        ServletOutputStream out=response.getOutputStream();
        IOUtils.copy(in, out);//把輸入流中的數據寫入到輸出流中。
        in.close();
    }

}

3)下載的細節

  1.顯示在下載框中的中文名稱時,會出現亂碼。

    *FireFox:Base64編碼。

    * 其餘大部分瀏覽器:URL編碼。

 

    通用方案:filename=new String(filename.getBytes("GBK"),  "ISO-8859-1");

 

    // 用來對下載的文件名稱進行編碼的!
        public static String filenameEncoding(String filename, HttpServletRequest request) throws IOException {
            String agent = request.getHeader("User-Agent"); //獲取瀏覽器
            if (agent.contains("Firefox")) {
                BASE64Encoder base64Encoder = new BASE64Encoder();
                filename = "=?utf-8?B?"
                        + base64Encoder.encode(filename.getBytes("utf-8"))
                        + "?=";
            } else if(agent.contains("MSIE")) {
                filename = URLEncoder.encode(filename, "utf-8");
            } else {
                filename = URLEncoder.encode(filename, "utf-8");
            }
            return filename;
        }

對中文(不亂嗎)名稱文件的下載:

package com.xjs.web.servlet;

import java.io.FileInputStream;
import java.io.IOException;
import java.net.URLEncoder;

import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.io.IOUtils;

import sun.misc.BASE64Encoder;



public class Download1Servlet extends HttpServlet {

    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        /*
         * 兩個頭一個流
         * 1.Content-Type
         * 2.Content-Disposition
         * 3.流  下載文件的數據
         */
        String filename="G:/金泰妍.mp3";
        
        //爲了使下載框中顯示中文文件名稱不出亂碼!
//        String framename=new String("金泰妍.mp3".getBytes("GBK"),"ISO-8859-1");
        
        String framename=filenameEncoding("金泰妍.mp3", request);
        
        //經過ServletContent的getMimeTypeZ()方法獲得文件的MIME類型
        String contentType = this.getServletContext().getMimeType(filename);
        
        String contentDisposition="attachment;filename="+framename;
        
        FileInputStream in=new FileInputStream(filename);
        
        //設置頭
        response.setHeader("Content-Type", contentType);
        response.setHeader("Content-Disposition", contentDisposition);
        
        //獲取綁定響應客戶端的流
        ServletOutputStream out=response.getOutputStream();
        IOUtils.copy(in, out);//把輸入流中的數據寫入到輸出流中。
        in.close();
    }

    // 用來對下載的文件名稱進行編碼的!
        public static String filenameEncoding(String filename, HttpServletRequest request) throws IOException {
            String agent = request.getHeader("User-Agent"); //獲取瀏覽器
            if (agent.contains("Firefox")) {
                BASE64Encoder base64Encoder = new BASE64Encoder();
                filename = "=?utf-8?B?"
                        + base64Encoder.encode(filename.getBytes("utf-8"))
                        + "?=";
            } else if(agent.contains("MSIE")) {
                filename = URLEncoder.encode(filename, "utf-8");
            } else {
                filename = URLEncoder.encode(filename, "utf-8");
            }
            return filename;
        }
}
相關文章
相關標籤/搜索