在 Java 專案開發中,文件操作是高頻需求。雖然 JDK 提供了 java.io 與 java.nio 套件,但針對業務場景封裝一個通用的工具類,能大幅減少樣板代碼,提升開發效率。本文介紹一個實用的 FileUtil 類,涵蓋文件/目錄複製、刪除、儲存、獲取文件名與副檔名等核心功能。
copy(File inputFile, File outputFile, boolean isOverWrite) 方法支援單文件與整個目錄樹的複製。內部透過私有方法 copyPri 遞歸處理子目錄,copySimpleFile 以 1KB 緩衝區進行流式讀寫,確保大文件不會導致記憶體溢出。
delete(File file) 封裝了遞歸刪除邏輯。先刪除子文件/子目錄,最後刪除自身。若刪除失敗會拋出 RuntimeException,方便上層捕獲處理。
提供兩個 save 重載:
save(byte[] content, File file):直接寫入位元組陣列。save(InputStream streamIn, File file):從輸入流讀取,使用 8KB 緩衝區,自動建立父目錄。getFilenameExtension(String path):提取副檔名(不含點號)。getFilename(String path):提取完整文件名(含副檔名)。兩者均處理 null 輸入與路徑分隔符兼容性。
package com.itjh.javaUtil;
import java.io.*;
public class FileUtil {
private static final String FOLDER_SEPARATOR = "/";
private static final char EXTENSION_SEPARATOR = '.';
public static void copy(File inputFile, File outputFile, boolean isOverWrite) throws IOException {
if (!inputFile.exists()) {
throw new RuntimeException(inputFile.getPath() + " 源路徑不存在!");
}
copyPri(inputFile, outputFile, isOverWrite);
}
private static void copyPri(File inputFile, File outputFile, boolean isOverWrite) throws IOException {
if (inputFile.isFile()) {
copySimpleFile(inputFile, outputFile, isOverWrite);
} else {
if (!outputFile.exists()) outputFile.mkdir();
for (File child : inputFile.listFiles()) {
copy(child, new File(outputFile.getPath() + "/" + child.getName()), isOverWrite);
}
}
}
private static void copySimpleFile(File inputFile, File outputFile, boolean isOverWrite) throws IOException {
if (outputFile.exists()) {
if (isOverWrite) {
if (!outputFile.delete()) throw new RuntimeException(outputFile.getPath() + " 無法覆蓋!");
} else return;
}
try (InputStream in = new FileInputStream(inputFile);
OutputStream out = new FileOutputStream(outputFile)) {
byte[] buffer = new byte[1024];
int read;
while ((read = in.read(buffer)) != -1) out.write(buffer, 0, read);
}
}
public static void delete(File file) { deleteFile(file); }
private static void deleteFile(File file) {
if (file == null || !file.exists()) return;
if (!file.isDirectory()) {
if (!file.delete()) throw new RuntimeException(file.getPath() + " 刪除失敗!");
return;
}
for (File child : file.listFiles()) deleteFile(child);
file.delete();
}
public static String getFilenameExtension(String path) {
if (path == null) return null;
int extIndex = path.lastIndexOf(EXTENSION_SEPARATOR);
if (extIndex == -1) return null;
int folderIndex = path.lastIndexOf(FOLDER_SEPARATOR);
if (folderIndex > extIndex) return null;
return path.substring(extIndex + 1);
}
public static String getFilename(String path) {
if (path == null) return null;
int separatorIndex = path.lastIndexOf(FOLDER_SEPARATOR);
return (separatorIndex != -1) ? path.substring(separatorIndex + 1) : path;
}
public static void save(byte[] content, File file) throws IOException {
if (file == null) throw new RuntimeException("儲存文件不能為空");
if (content == null) throw new RuntimeException("文件流不能為空");
save(new ByteArrayInputStream(content), file);
}
public static void save(InputStream streamIn, File file) throws IOException {
if (file == null) throw new RuntimeException("儲存文件不能為空");
if (streamIn == null) throw new RuntimeException("文件流不能為空");
if (!file.getParentFile().exists()) file.getParentFile().mkdirs();
try (OutputStream streamOut = new FileOutputStream(file)) {
byte[] buffer = new byte[8192];
int bytesRead;
while ((bytesRead = streamIn.read(buffer)) != -1) streamOut.write(buffer, 0, bytesRead);
} finally {
streamIn.close();
}
}
}
Files.copy、Files.walkFileTree) 以獲得更好性能。static,無狀態,線程安全。這個 FileUtil 類將常見文件操作封裝為靜態方法,代碼結構清晰、異常處理明確,適合直接集成到專案公共模組中。後續可擴展支援壓縮解壓、MD5 校驗等功能,構建更完整的文件處理工具箱。