1. 程式人生 > >文件上傳和下載

文件上傳和下載

分析 bst 通過 zemax get char 避免 獲取文件 list

一、文件的上傳和下載
  1、文件上傳的原理分析
    1.1文件上傳的必要前提:
      a、提供form表單,method必須是post
      b、form表單的enctype必須是multipart/form-data
      c、提供input type="file"類的上傳輸入域
    1.2enctype屬性
      作用:告知服務器請求正文的MIME類型。(請求消息頭:Content-Type作用是一致的)
      可選值:


        application/x-www-form-urlencoded(默認):
      正文:name=admin&password=123
      服務器獲取數據:String name = request.getParameter("name");

        multipart/form-data:
      正文:對每個域分開上傳
      服務器獲取數據:request.getParameter(String)方法獲取指定的表單字段字符內容,
              但文件上傳表單已經不在是字符內容,而是字節內容,所以失效。
              所以使用request.getInputStream()獲取數據


      文件上傳:解析請求正文的每部分的內容。

  2、借助第三方的上傳組件實現文件上傳
    2.1 fileupload概述
        fileupload是由apache的commons組件提供的上傳組件。它最主要的工作就是幫我們解析request.getInputStream()。
      導入commons-fileupload相關jar包
        commons-fileupload.jar,核心包;
        commons-io.jar,依賴包。

    2.2 fileupload的核心類有:
      DiskFileItemFactory、ServletFileUpload、FileItem。

    2.3 fileupload簡單應用
      使用fileupload組件的步驟如下:
        1. 創建工廠類DiskFileItemFactory對象:
          DiskFileItemFactory factory = new DiskFileItemFactory()
        2. 使用工廠創建解析器對象:
          ServletFileUpload fileUpload = new ServletFileUpload(factory)
        3. 使用解析器來解析request對象:


          List<FileItem> list = fileUpload.parseRequest(request)


      FileItem對象對應一個表單項(表單字段)。可以是文件字段或普通字段
        boolean isFormField():判斷當前表單字段是否為普通文本字段,如果返回false,說明是文件字段;
        String getFieldName():獲取字段名稱,例如:<input type=”text” name=”username”/>,返回的是username;
        String getString():獲取字段的內容,如果是文件字段,那麽獲取的是文件內容,當然上傳的文件必須是文本文件;
        String getName():獲取文件字段的文件名稱;(a.txt)
        String getContentType():獲取上傳的文件的MIME類型,例如:text/plain。
        int getSize():獲取上傳文件的大小;
        InputStream getInputStream():獲取上傳文件對應的輸入流;
        void write(File):把上傳的文件保存到指定文件中。
        delete(): 刪除在上傳大文件時產生的臨時存儲文件。


  3、文件上傳時要考慮的幾個問題(經驗分享)

    a、解決獲得客戶端文件名時可能帶有全路徑的問題(造成服務端存盤有雙根目錄)

      filename = FilenameUtils.getName(filename);
    a、保證服務器的安全
      把保存上傳文件的目錄放在用戶直接訪問不到的地方。
      String directoryRealPath = this.getServletContext().getRealPath("/WEB-INF/upload");

    b、避免文件被覆蓋
      讓文件名唯一即可
      filename = UUID.randomUUID() + "_" + filename; (或者)
      filename.substring(filename.lastIndexOf(File.separator)+1);
    c、避免同一個文件夾中的文件過多
      方案一:按照日期進行打散存儲目錄
      private String makeChildDirectory(File storeDirectory) {

        SimpleDateFormat sdf =new SimpleDateFormat("yyyy-MM-dd");
        String dateDirectory = sdf.format(new Date());
        //只管創建目錄 File file = new File(storeDirectory,dateDirectory);
        if(!file.exists()){ file.mkdirs(); }

        return dateDirectory;
      }

      方案二:用文件名的hashCode計算打散的存儲目錄:二級目錄
      private String makeChildDirectory(File storeDirectory, String filename) {
        int hashcode = filename.hashCode();// 返回字符轉換的32位hashcode碼
        System.out.println(hashcode);
        String code = Integer.toHexString(hashcode); // 把hashcode轉換為16進制的字符
                                // abdsaf2131safsd
        System.out.println(code);
        String childDirectory = code.charAt(0) + File.separator+ code.charAt(1); // a/b
            // 創建指定目錄
        File file = new File(storeDirectory, childDirectory);
        if (!file.exists()) {
          file.mkdirs();
        }
        return childDirectory;
      }

    d、限制文件的大小:web方式不適合上傳大的文件
      單個文件大小:
        ServletFileUpload.setFileSizeMax(字節)
      總文件大小:(多文件上傳)
        ServletFileUpload.setSizeMax(字節)

    e、上傳字段用戶沒有上傳的問題
      通過判斷文件名是否為空即可

    f、臨時文件的問題
      DiskFileItemFactory:
      作用:產生FileItem對象
        內部有一個緩存,緩存大小默認是10Kb。如果上傳的文件超過10Kb,用磁盤作為緩存。
        存放緩存文件的目錄在哪裏?默認是系統的臨時目錄。

        如果自己用IO流實現的文件上傳,要在流關閉後,清理臨時文件。
        FileItem.delete();

文件上傳和下載