文件上傳與下載

文件上傳與下載

1. 文件上傳

為了能上傳文件,必須將表單的 method 設置為 POST,并將 enctype 設置為 multipart/form-data

有兩種實現文件上傳的方式:

  • 底層使用 Apache Commons FileUpload 包

  • 底層使用 Servlet 3.1 內置的文件上傳功能

無論是哪種方式,其使用方式都是一樣的,將 file 類型的請求參數綁定到請求處理方法的特定類型的參數上:

  • CommonsMultipartFile(commons-fileupload)

  • MultipartFile(Servlet 3.1)

Web 3.0 的文件上傳

普通的表單(form)元素無法直接上傳文件,必須通過「特殊處理」。

對上傳文件功能而言,有些特殊的地方:

  • form 表單內,要添加控件 <input type="file" name="myfile">
  • form 表單的提交方式必須是 post 方式
  • form 表單的內容格式要定義成 multipart/form-data 格式
<form action="..." method="post" enctype="multipart/form-data">...
</form>

enctype="multipart/form-data" 表示表單元素中的 input 數據以二進制的方式發送到服務端。此時如果是普通的 input 數據,無法像之前一樣從 request 中直接獲得。

對于上傳文件的的大小問題,慣例是:

  • 足夠小的文件,先接收到內存中,最后寫入磁盤。
  • 稍大的文件,寫入磁盤臨時文件,最后寫入最終目的地。
  • 大型文件,禁止上傳。

在 Web 3.0 之前 使用 commons-fileupload 庫是最常見的上傳辦法。當 Servlet 的設計者意識到文件上傳的重要性后,在 Web 3.0 中它就成了一項內置的特性。

Web 3.0 中的文件上傳主要圍繞著 MultipartConfig 注解和 Part 接口。

@MultipartConfig 注解
屬性說明
fileSizeThreshold
可選屬性
超過該值大小的文件,在上傳過程中,將被寫入磁盤臨時文件,而不是保存在內存中。
maxFileSize
可選屬性
每個上傳文件的大小上限。
maxRequestSize
可選屬性
一次請求(可能包含多個上傳)的大小上限。
@WebServlet(urlPatterns="/hello.do")
@MultipartConfig(maxFileSize = 5*1024*1024)
public class HelloServlet extends HttpServlet  {...
}
Part 接口

在一個表單(Form)中,無論是否有文件上傳控件,Servlet 3.0 都會將這些表單控件對應成代碼中的一個 Part 對象。

通過 request 對象的 .getParts() 方法可以獲得所有的這些 Part 對象。

Collection<Part> parts = request.getParts();

在一個或多個部分組成的請求中,每一個表單域(包括非文本域),都將被轉換成一個 Part 。

普通文本域和文件上傳域的區別在于,其 Part 對象的 .getContentType() 方法返回值的不同。對于普通文本域的 Part 對象而言,該方法返回 null 。

for (Part part : parts) {if (part.getContentType() == null) {System.out.println("普通文本域");}else {System.out.println("文件上傳域");}
}

補充,如果是要獲取普通文本域的值,其實直接使用正常 request.getParameter() 就行。

每一個 Part 分為「頭」和「體」兩部分。普通文本域只有頭部,而文件上傳域則有頭有體。

普通文本域的頭部形式為:

content-disposition:form-data; name="域名"

上傳文本域的頭部形式為:

content-type:內容類型
content-disposition:form-data; name="域名"; filename="文件名"

對我們而言,需要的是文本上傳域中的 content-disposition 中的 filename 部分。

String header = part.getHeader("content-disposition"); 
// 內容為 form-data; name="域名"; filename="文件名"

通常會使用工具類,將 content-disposition 中的 filename 中的值截取出來。

private String getFileName(String header) {String[] arr = header.split("; ");String item = null;for (String cur : arr) {// System.out.println("debug: " + cur);if (cur.startsWith("filename=")) {item = cur;break;}}int start = item.indexOf('"')+1;int end = item.lastIndexOf('"');String filename = item.substring(start, end);// System.out.println(filename);return filename;
}

Part 對象直接提供了方法將上傳文件的內容寫入盤:

String savePath = request.getServletContext().getRealPath("/WEB-INF/uploadFile/");
String filePathName = savePath + File.separator + fileName; // 目標文件路徑名
part.write(filePathName); // 把文件寫到指定路徑

Part 的其它常用方法

方法說明
getContentType()獲得 Part 的內容類型。如果 Part 是普通文本,那么返回 null 。
該方法可以用于區別是普通文本域,還是文件上傳域。
getHeader()該方法用于獲取指定的標頭的值。
對于上傳文本域的 Part,該參數有 content-type 和 content-disposition
對于普通文本域,則只有 content-disposition 一種。
getName()無論是普通文本域 Part ,還是文件上傳域 Part ,都是獲得域名值。
write()將上傳文件寫入磁盤中。
delete()手動刪除臨時文件
getInputStream()以 InputStream 形式返回上傳文件的內容。
利用 commons-fileupload 文件上傳

利用 commons-fileupload 文件上傳需要利用引入 commons-fileupload 包(它依賴于 commons-io 包)

<dependency><groupId>commons-fileupload</groupId><artifactId>commons-fileupload</artifactId><version>1.4</version>
</dependency>

作為 Servlet 內置上傳功能之前的『準標準』,Servlet 在引入內置上傳功能時借鑒了 commons-fileupload 的實現方式。因此,在了解 Servlet 內置上傳功能之后,再回頭看 commons-fileupload 文件上傳時,你會發現它們的基本邏輯/大道理時一樣的,只不過 commons-fileupload 的實現會羅嗦一些

在 Servlet 內置的上傳功能中,從 request 中獲得的是一個 Part[],其中的每一個 Part 對象對應著表單中的一個表單域(Form Field)。而 commons-fileupload 中我們從 request 中獲得的是一個 List<FileItem>,commons-fileupload 中使用 FileItem 來對應每一個表單域,起到和 Part 一樣的作用。

commons-fileupload 的羅嗦體現在以下幾個方面:

  • commons-fileupload 不能對 Servlet 使用注解,因此相關的上傳配置需要通過編碼實現。
  • commons-fileupload 不能使用 request.getParameter()

為了能夠從 request 中獲得 List<FileItem>,你需要兩個對象:

// 創建上傳所需要的兩個對象
DiskFileItemFactory factory = new DiskFileItemFactory();  // 磁盤文件對象
ServletFileUpload sfu = new ServletFileUpload(factory);   // 文件上傳對象

如果不做出設置,那么相關設置則采用默認值。

// 設置上傳過程中所收到的數據是『存內存』還是『存磁盤』的閾值
factory.setSizeThreshold(100 * 1024); 
// 設置磁盤臨時文件的保存目錄
factory.setRepository(new File("D:/upload"));// 設置解析文件上傳中的文件名的編碼格式,解決上傳文件名中文亂碼問題
sfu.setHeaderEncoding("utf-8");
// 限制單個文件的大小
sfu.setFileSizeMax(10*1024);
// 限制上傳的總文件大小
sfu.setSizeMax(100*1024);

在創建文件上傳對象(并作出相應設置)之后,我們可以通過它從 request 中獲取我們所需要的 List<FileItem>

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

FileItem 自帶了方法,可以判斷當前的 FileItem 對應的是頁面上的普通文本域,還是文件上傳域:

for (FileItem item : list) {if (item.isFormField()) {System.out.println("普通文本域");}else {    System.out.println("文件上傳域");}
}

由于 commons-fileupload 中無法使用 request.getParameter(),因此,為了獲得普通文本域中的數據,需要使用 FileItem 自己的方法:

for (FileItem item : list) {if (item.isFormField()) {String fieldName = item.getFieldName();         // 例如:username / passwordString fieldValue = item.getString("UTF-8");    // 例如,tom / 123456System.out.println(fieldName + ": " + fieldValue);}else {    System.out.println("文件上傳域");}
}

由于 commons-fileupload 引用了 commons-io,所以,將上傳的文件內容寫入磁盤倒是十分簡單:

for (FileItem item : list) {if (item.isFormField()) {...}else {    System.out.println("文件上傳域");// 創建輸出文件String name = item.getName();// 獲取上傳文件的名字String outPath = "D:/upload/" + name;FileOutputStream output = new FileOutputStream(new File(outPath));// 獲得上傳文件字節流InputStream input = item.getInputStream(); // 使用 IOUtils 工具將輸入流中的數據寫入到輸出流。IOUtils.copy(input, output);System.out.println("上傳成功!保存的路徑為:" + outPath);input.close();      // 關閉輸入流output.close();     // 關閉輸出流item.delete();      // 刪除處理文件上傳時生成的臨時文件}
}

2. 文件下載

內容類型文件擴展名描述
text/plaintxt文本文件(包括但不僅包括txt)
application/msworddocMicrosoft Word
application/pdfpdfAdobe Acrobat
application/zipzipwinzip
audio/mpegmp3mp3 音頻文件
image/gifgifCOMPUSERVE GIF 圖像
image/jpegjpeg jpgJPEG 圖像
image/pngpngPNG 圖像

詳細 MIME 參見 網址 。

相對于上傳而言,下載文件較為簡單,只需要完成兩步:

  1. 設置響應的內容類型。
  2. 添加一個 content-disposition 到響應標頭(addHeader()方法),其值為:attachment; filename=文件名
  3. 通過 resp 對象獲得輸出流,將文件內容發送至客戶端。
resp.setContentType("text/plain");      // step 1
resp.setHeader("content-disposition", "attachment;filename=" + URLEncoder.encode("D:/note.txt", "UTF-8")); // step 2InputStream is = new FileInputStream(new File("D:/note.txt"));
OutputStream out = resp.getOutputStream();byte[] buffer = new byte[1024];
int n = 0;
while ((n = is.read(buffer)) > 0) {out.write(buffer, 0, n);            // step 3
}is.close();
out.close();
System.out.println("下載成功");

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/696954.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/696954.shtml
英文地址,請注明出處:http://en.pswp.cn/news/696954.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

如何計算文件哈希值(MD5值)

生成文件hash值的用途 哈希值&#xff0c;即HASH值&#xff0c;是通過對文件內容進行加密運算得到的一組二進制值&#xff0c;主要用途是用于文件校驗或簽名。正是因為這樣的特點&#xff0c;它常常用來判斷兩個文件是否相同。 比如&#xff0c;從網絡上下載某個文件&#xff0…

MySQL主從同步

MySQL主從同步&#xff08;復制&#xff09;是一種數據復制技術&#xff0c;用于將數據從一個MySQL數據庫&#xff08;稱為“主”&#xff09;復制到另一個或多個MySQL數據庫&#xff08;稱為“從”&#xff09;。這個過程通常用于負載均衡、數據備份、災難恢復和其他類似場景。…

C++ Primer Plus 筆記(持續更新)

編譯器的正解 數據&#xff0b;算法程序 賦值從右向左進行 cin&#xff0c;cout的本質也是對象 類和對象的解釋

centerOS docker搭建flowable,流程引擎

1、準備一個mysql數據庫&#xff0c;庫名為flowable 2、mysql驅動下載&#xff0c;下載地址為&#xff1a; https://mvnrepository.com/artifact/mysql/mysql-connector-java此處使用的是8.0.22版本的驅動&#xff0c;且數據庫必須使用版本8&#xff0c;否則第二次啟動報錯 3、…

OpenAI文生視頻大模型Sora概述

Sora&#xff0c;美國人工智能研究公司OpenAI發布的人工智能文生視頻大模型&#xff08;但OpenAI并未單純將其視為視頻模型&#xff0c;而是作為“世界模擬器” &#xff09;&#xff0c;于2024年2月15日&#xff08;美國當地時間&#xff09;正式對外發布。 Sora可以根據用戶…

samber/lo 庫的使用方法:type

samber/lo 庫的使用方法&#xff1a;type samber/lo 是一個 Go 語言庫&#xff0c;提供了一些常用的集合操作函數&#xff0c;如 Filter、Map 和 FilterMap。 這個庫函數太多&#xff0c;因此我決定按照功能分別介紹&#xff0c;本文介紹的是 samber/lo 庫中type相關的函數。匯…

Redis中的AOF重寫到底是怎么一回事

首先我們知道AOF和RDB都是Redis持久化的方法。RDB是Redis DB&#xff0c;一種二進制數據格式&#xff0c;這樣就是相當于全量保存數據快照了。AOF則是保存命令&#xff0c;然后恢復的時候重放命令。 AOF隨著時間推移&#xff0c;會越來越大&#xff0c;因為不斷往里追加命令。…

哪些行業適合做小程序?零售電商、餐飲娛樂、旅游酒店、教育生活、醫療保健、金融社交、體育健身、房產汽車、企管等,你的行業在其中么?

引言 在當今數字化時代&#xff0c;小程序成為了各行各業快速發展的數字工具之一。它的輕便、靈活的特性使得小程序在多個行業中找到了廣泛的應用。本文將探討哪些行業適合開發小程序&#xff0c;并介紹各行業中小程序的具體應用。 一、零售和電商 在當今數字化的商業環境中&…

C++ RAII

RAII定義 RAII&#xff08;Resource Acquisition Is Initialization&#xff09;是C編程中的一種重要的資源管理技術。它的核心思想是&#xff1a;資源的獲取應該在對象的構造階段進行&#xff0c;而資源的釋放則應該在對象的析構階段進行。通過利用C對象的生命周期和析構函數…

C#之WPF學習之路(2)

目錄 控件的父類 DispatcherObject類 DependencyObject類 DependencyObject 類的關鍵成員和方法 Visual類 Visual 類的主要成員和方法 UIElement類 UIElement 類的主要成員和功能 FrameworkElement類 FrameworkElement 類的主要成員和功能 控件的父類 在 WPF (Windo…

谷粒商城篇章9 ---- P248-P261/P292-P294 ---- 消息隊列【分布式高級篇六】

目錄 1 消息隊列(Message Queue)簡介 1.1 概述 1.2 消息服務中兩個重要概念 1.3 消息隊列主要有兩種形式的目的地 1.4 JMS和AMQP對比 1.5 應用場景 1.6 Spring支持 1.7 SpringBoot自動配置 1.7 市面上的MQ產品 2 RabbitMQ 2.1 RabbitMQ簡介 2.1.1 RabbitMQ簡介 2…

什么是Elasticsearch SQL

什么是Elasticsearch SQL 一. 介紹二. SQL 入門 前言 這是我在這個網站整理的筆記,有錯誤的地方請指出&#xff0c;關注我&#xff0c;接下來還會持續更新。 作者&#xff1a;神的孩子都在歌唱 一. 介紹 Elasticsearch SQL 是一個 X-Pack 組件&#xff0c;允許針對 Elasticsea…

通俗易懂理解G-GhostNet輕量級神經網絡模型

一、參考資料 原始論文&#xff1a;[1] IJCV22 | 已開源 | 華為GhostNet再升級&#xff0c;全系列硬件上最優極簡AI網絡 二、G-GhostNet相關介紹 G-GhostNet 又稱為 GhostNetV1 的升級版&#xff0c;是針對GPU優化的輕量級神經網絡。 1. 摘要 GhostNetV1 作為近年來最流行…

Leetcode 611.有效三角形的個數

題目 給定一個包含非負整數的數組 nums &#xff0c;返回其中可以組成三角形三條邊的三元組個數。 示例 1: 輸入: nums [2,2,3,4] 輸出: 3 解釋:有效的組合是: 2,3,4 (使用第一個 2) 2,3,4 (使用第二個 2) 2,2,3示例 2: 輸入: nums [4,2,3,4] 輸出: 4提示: 1 < nums…

Android的LiveData

LiveData 是一種可觀察的數據存儲器類。與常規的可觀察類不同&#xff0c;LiveData 具有生命周期感知能力&#xff0c;意指它遵循其他應用組件&#xff08;如 activity、fragment 或 service&#xff09;的生命周期。這種感知能力可確保 LiveData 僅更新處于活躍生命周期狀態的…

ChatGPT在醫學領域的應用與前景

標題&#xff1a; ChatGPT在醫學領域的應用與前景 正文&#xff1a; 隨著人工智能技術的不斷進步&#xff0c;ChatGPT等語言模型在醫學領域的應用逐漸深入&#xff0c;展現出其巨大的潛力和廣闊的發展前景。作為一個高級的自然語言處理工具&#xff0c;ChatGPT能夠理解和生成…

WPF 開發調試比較:Visual Studio 原生和Snoop調試控制臺

文章目錄 前言運行環境簡單的WPF代碼實現一個簡單的ListBoxVisual Studio自帶代碼調試熱重置功能測試實時可視化樹查找窗口元素顯示屬性 Snoop調試使用Snoop簡單使用調試控制臺元素追蹤結構樹Visual/可視化結構樹Logical/本地代碼可視化樹AutoMation/自動識別結構樹 WPF元素控制…

基于springboot+vue的房屋租賃管理系統(前后端分離)

博主主頁&#xff1a;貓頭鷹源碼 博主簡介&#xff1a;Java領域優質創作者、CSDN博客專家、阿里云專家博主、公司架構師、全網粉絲5萬、專注Java技術領域和畢業設計項目實戰&#xff0c;歡迎高校老師\講師\同行交流合作 ?主要內容&#xff1a;畢業設計(Javaweb項目|小程序|Pyt…

【OpenAI官方課程】第四課:ChatGPT文本推斷Summarizing

歡迎來到ChatGPT 開發人員提示工程課程&#xff08;ChatGPT Prompt Engineering for Developers&#xff09;&#xff01;本課程將教您如何通過OpenAI API有效地利用大型語言模型&#xff08;LLM&#xff09;來創建強大的應用程序。 本課程由OpenAI 的Isa Fulford和 DeepLearn…

手拉手Vite+Vue3+TinyVue+Echarts+TailwindCSS

技術棧springboot3hutool-alloshi-coreVue3viteTinyVueEchartsTailwindCSS軟件版本IDEAIntelliJ IDEA 2022.2.1JDK17Spring Boot3.1hutool-all5.8.18oshi-core6.4.1Vue35.0.10vite5.0.10axios1.6.7echarts5.4.3 ECharts是一個使用 JavaScript 實現的開源可視化庫&#xff0c;可…