12、文件上傳

文件上傳概述

將本地的文件通過流寫入到服務器的過程。

  • QQ上傳照片
  • 招聘網站上傳簡歷

文件上傳技術

  • JSPSmartUpload:應用在JSP上的文件上傳和下載的組件。
  • FileUpload:應用在java環境上的文件上傳的功能。
  • Servlet3.0:提供文件上傳的功能。
  • Struts2:提供文件上傳的功能。

文件上傳的要素:

  • 表單提交的方式需要時POST
  • 表單中需要有文件上傳的組件,表單有< input type=“file” >元素,需要有name屬性和值。
  • 表單< enctype=“multipart/form-data” >

文件上傳的原理分析

在這裏插入圖片描述

代碼實現

  • 引入jar包
    在這裏插入圖片描述
  • 編寫頁面
    在這裏插入圖片描述
  • 編寫文件上傳的Servlet
/**
 * 文件上傳的Servlet 
 */
public class UploadServlet extends HttpServlet {
	
	
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		try {
			//1、創建磁盤文件項的工廠
			DiskFileItemFactory diskFileItemFactory = new DiskFileItemFactory();
			//2、創建一個核心的解析類
			ServletFileUpload fileUpload = new ServletFileUpload(diskFileItemFactory);
			//3、利用核心類解析request,解析後會得到多個部分,返回一個List集合,List集合裝的是每個部分的內容(FileItem文件項)
			List<FileItem> list = fileUpload.parseRequest(request);
			//4、遍歷list集合,會得到代表每個部分的文件項的對象,根據文件判斷是否是文件上傳項。
			for (FileItem fileItem : list) {
				//判斷文件是普通項還是上傳項
				if(fileItem.isFormField()) {
					//普通項,接收普通的值(表單的enctype變更,所以不能用request.getParameter())
					String name = fileItem.getFieldName();
					//獲得普通項的值
					String value = fileItem.getString("UTF-8");
					System.out.println(name+"    "+value);
				}else {
					//文件上傳項
					//獲得文件上傳項文件的名稱
					String filename =  fileItem.getName();
					//獲得文件上傳項文件的數據
					InputStream is = fileItem.getInputStream();
					//獲得文件上傳的路徑:磁盤絕對路徑
					String realPath = getServletContext().getRealPath("/upload");
					//創建一個輸出流,寫入到設置的路徑中
					OutputStream os = new FileOutputStream(realPath+"/"+filename);
					//兩個流對接
					int len = 0;
					byte[] b = new byte[1024];
					while((len = is.read(b)) != -1) {
						os.write(b,0,len);	
					}
					is.close();
					os.close();
				}
				
			}
		} catch (FileUploadException e) {
			e.printStackTrace();
		}
		
	
	}

	
	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		doGet(request, response);
	}

}

文件上傳的API

  • DiskFileItemFactory磁盤文件項工廠
    在這裏插入圖片描述
  • ServletFileUpload核心解析類
    • 構造方法:
      • ServletFileUpload();
      • ServletFileUpload(FileItemFactory fileItemFactory);
    • 方法:
      • isMultipartContext():判斷表單的enctype屬性是否正確;
      • parseRequest():解析Request對象,返回一個List集合(每個部分的對象FileItem);
      • setFileSizeMax():設置單個文件上傳大小;
      • setSizeMax():設置文件上傳總大小;
      • setProgressLstener():設置監聽文件上傳進度;
      • setHeaderEncoding():設置中文文件名的上傳亂碼問題
  • FileItem文件項
    • isFormFiled():判斷表單是普通項還是文件上傳項,如果爲true則代表爲普通項;
    • getFileName():獲得普通項名稱;
    • getString():獲得普通項的值;
    • getName():獲得上傳項的名稱;
    • getInputStream():獲得上傳的文件內容;
    • getSize():獲得文件上傳的文件大小;
    • delete():刪除文件上傳過程中的臨時文件;

JS控制多文件上傳

在這裏插入圖片描述

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<script>
	 function add(){
		 var div1Element = document.getElementById("div1");
		 div1Element.innerHTML += "<div><input type='file' name='upload'><input type='button' value='刪除' οnclick='del(this)'></div>";
	 }
	 function del(who){
		 var divv = who.parentNode;
		 divv.parentNode.removeChild(divv);
	 }

</script>
</head>
<body>
<h1>多文件上傳</h1>
	<form action=" ${pageContext.request.contextPath }/UploadServlet " method="post" enctype="multipart/form-data">
		<input type="button" value="添加" onclick="add()">	
		<input type="submit" value="上傳">	
		<div id="div1"> </div> <br/>
	
	
	</form>

</body>
</html>

文件上傳中兼容瀏覽器的問題

IE老版本的瀏覽器會出現文件名獲取錯誤的問題,因爲獲取文件名稱的時候會帶有路徑。edge也有此問題。
在這裏插入圖片描述
解決代碼:

//文件上傳項
//獲得文件上傳項文件的名稱
String filename =  fileItem.getName();
//System.out.println("文件名:"+filename);
//找到最後一個斜槓
int idx = filename.lastIndexOf("\\");
if(idx != -1) {
	//說明找到了,要截掉路徑
	filename = filename.substring(idx+1);
}

文件上傳同一個目錄下文件同名的問題

使用唯一文件名進行解決

  • 編寫工具類
package com.itheima.utils;

import java.util.UUID;

/**
 * 文件上傳的工具類
 * @author wj156
 *
 */

public class UploadUtils {

	/**
	 * 傳遞一個文件名,返回一個唯一的文件名。
	 */
	public static String getUuidFileName(String fileName) {
		//javaAPI 中有一個類UUID可以產生隨機的字符串
		//獲得文件的擴展名
		int index = fileName.lastIndexOf(".");
		String extetions = fileName.substring(index);
		//隨機生成字符串並返回
		return UUID.randomUUID().toString()+extetions;
	}
}
  • 引入工具類
//得到唯一文件名
String uuidFileName = UploadUtils.getUuidFileName(filename);

文件上傳同一個目錄下文件過多的問題

目錄下文件過多,打開會卡頓,且影響讀寫操作。
解題思路:目錄分離

  • 按時間分離:按月、周、天等
  • 按用戶分離:按張三、李四
  • 按個數分離:一個目錄存放3000個文件
  • 按目錄分離算法:按某種特定算法進行分離
    • 上傳一個文件,得到唯一文件名,獲取hashcode值(32位int類型的值),讓hashcode的值&0xf,得出值爲一級目錄;讓hashcode右移4位&0xf,得出這個值位二級目錄,以此類推。
      在這裏插入圖片描述
      工具類中編寫方法:
	/**
	 * 目錄分離算法的實現
	 */
public static String getRealPath(String uuidFileName) {
	int code1 = uuidFileName.hashCode();
	int d1 = code1 & 0xf; //獲得一級目錄
	int code2 = code1 >>> 4; //右移4位
	int d2 = code2 & 0xf; //獲得二級目錄
	// 。。。。
	return "/"+d1+"/"+d2;
}

應用:

//進行目錄分離:
String path = UploadUtils.getRealPath(uuidFileName);
String newPath = realPath+path;
File file = new File(newPath);
if(!file.exists()) {
	file.mkdir();
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章