JSP 文件操作全攻略:File 類、IO 流體系、RandomAccessFile、上傳下載實戰
文件操作是 Web 開發常見需求。本文系統梳理 File 類元數據操作、四大流體系(字節/字符/緩衝/隨機訪問)、文件上傳與下載完整實戰代碼,適合 JSP/Servlet 初學者建立完整 IO 知識體系。
一、File 類:文件與目錄元數據操作
構造方法
new File(String pathname); // 絕對/相對路徑
new File(String parent, String child); // 父目錄 + 子路徑
new File(File parent, String child); // File 對象 + 子路徑
常用方法速查
| 方法 | 返回值 | 說明 |
getName() | String | 文件名 |
exists() | boolean | 是否存在 |
isFile() / isDirectory() | boolean | 判斷類型 |
length() | long | 文件大小(字節) |
getAbsolutePath() | String | 絕對路徑 |
lastModified() | long | 最後修改時間(毫秒時間戳) |
mkdir() | boolean | 創建單級目錄 |
mkdirs() | boolean | 創建多級目錄 |
list() / listFiles() | String[] / File[] | 列出目錄內容 |
delete() | boolean | 刪除文件/空目錄 |
文件名過濾器範例
File dir = new File("d:/docs");
File[] txtFiles = dir.listFiles((d, name) -> name.endsWith(".txt"));
二、IO 流體系總覽
| 抽象基類 | 流向 | 處理單位 | 典型實現 |
InputStream | 輸入 | 字節 | FileInputStream, ByteArrayInputStream |
OutputStream | 輸出 | 字節 | FileOutputStream, ByteArrayOutputStream |
Reader | 輸入 | 字符 | FileReader, BufferedReader, InputStreamReader |
Writer | 輸出 | 字符 | FileWriter, BufferedWriter, OutputStreamWriter |
標準四步驟
- 指定源/目的地
- 創建流對象
- 讀/寫數據
- 關閉流(finally 或 try-with-resources)
三、字節流實戰
// 複製文件(字節流 + 緩衝數組)
try (FileInputStream in = new FileInputStream("src.jpg");
FileOutputStream out = new FileOutputStream("dest.jpg")) {
byte[] buf = new byte[8192];
int len;
while ((len = in.read(buf)) != -1) {
out.write(buf, 0, len);
}
}
四、字符流與編碼處理
字符流內部按 char(2 字節)處理,適合文本文件,避免中文亂碼。
// 指定編碼讀寫
try (FileReader fr = new FileReader("utf8.txt");
BufferedReader br = new BufferedReader(fr);
FileWriter fw = new FileWriter("out.txt", true); // append=true 追加模式
BufferedWriter bw = new BufferedWriter(fw)) {
String line;
while ((line = br.readLine()) != null) {
bw.write(line);
bw.newLine(); // 跨平台換行
}
}
五、緩衝流增強
BufferedReader.readLine():按行讀取(原生 Reader 無此能力)。
BufferedWriter.newLine() / flush():高效寫入。
六、RandomAccessFile:隨機讀寫
非流體系繼承,支援可讀可寫、任意位置定位,適合大文件斷點續傳、索引查詢。
// "rw" 模式:可讀可寫
try (RandomAccessFile raf = new RandomAccessFile("data.dat", "rw")) {
raf.seek(100); // 定位到第 100 字節
raf.writeInt(12345); // 寫入 int(4 字節)
raf.seek(100);
int val = raf.readInt(); // 讀取 int
System.out.println(raf.getFilePointer()); // 當前指針位置
}
| 方法 | 功能 |
seek(long pos) | 移動文件指針 |
getFilePointer() | 獲取當前指針位置 |
readUTF()/writeUTF() | 讀寫修改版 UTF-8 字符串 |
readLine() | 讀取文本行 |
七、文件上傳實戰(Servlet 3.0+ 原生支援)
前端表單(關鍵屬性)
<form action="uploadServlet" method="post" enctype="multipart/form-data">
<input type="file" name="myFile" />
<input type="submit" value="上傳" />
</form>
後端處理(Servlet 3.0 @MultipartConfig)
@WebServlet("/uploadServlet")
@MultipartConfig(maxFileSize = 1024*1024*10) // 10MB
public class UploadServlet extends HttpServlet {
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws IOException {
Part part = req.getPart("myFile");
String fileName = Paths.get(part.getSubmittedFileName()).getFileName().toString(); // 防路徑遍歷
part.write("d:/uploads/" + fileName); // 直接寫入磁碟
resp.getWriter().println("上傳成功:" + fileName);
}
}
舊版 JSP 腳本寫法(不推薦生產用):使用 request.getInputStream() 手動解析 multipart 數據,極易出錯,建議升級 Servlet 3.0+ 或引入 Apache Commons FileUpload。
八、文件下載實戰
@WebServlet("/download")
public class DownloadServlet extends HttpServlet {
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
File file = new File("d:/story/book.zip");
resp.setContentType("application/octet-stream");
resp.setHeader("Content-Disposition", "attachment; filename=\"" + file.getName() + "\"");
resp.setHeader("Content-Length", String.valueOf(file.length()));
try (FileInputStream in = new FileInputStream(file);
OutputStream out = resp.getOutputStream()) {
byte[] buf = new byte[4096];
int len;
while ((len = in.read(buf)) != -1) out.write(buf, 0, len);
}
}
}
| 響應頭 | 作用 |
Content-Disposition: attachment; filename=xxx | 觸發瀏覽器「另存為」對話框 |
Content-Type | 告知 MIME 類型,application/octet-stream 通用二進制 |
Content-Length | 支援斷點續傳與進度條 |