文件刪除看似簡單,實則暗藏目錄非空、路徑分隔符、符號鏈接、權限不足、并發修改等坑。本文提供兩個生產可用的靜態工具方法:delete(String path) 與 deleteAllFiles(File file),並對比差異、補充 NIO.2 現代寫法與避坑清單。
public static void delete(String path) {
File file = new File(path);
// 1. 不存在直接返回
if (!file.exists()) return;
// 2. 是文件直接刪除
if (file.isFile()) {
file.delete();
return;
}
// 3. 是目錄:遞歸刪除子項
if (file.isDirectory()) {
String[] children = file.list();
if (children == null) return; // 權限不足或 IO 錯誤
// 關鍵:確保路徑以分隔符結尾
if (!path.endsWith(File.separator)) {
path += File.separator;
}
for (String child : children) {
delete(path + child); // 遞歸
}
}
// 4. 最後刪除空目錄自身
file.delete();
}
public static void deleteAllFiles(File file) {
if (!file.exists()) return;
if (file.isFile()) {
file.delete();
return;
}
if (file.isDirectory()) {
File[] children = file.listFiles(); // 直接獲取 File[],無需手動拼路徑
if (children == null) return;
for (File child : children) {
deleteAllFiles(child); // 遞歸傳 File 對象
}
}
file.delete(); // 刪除空目錄
}
| 維度 | 字符串版 delete(String) | File 版 deleteAllFiles(File) |
|---|---|---|
| 路徑拼接 | 手動 path + File.separator + child,易出錯 | File.listFiles() 直接返回完整 File 對象,無需拼接 |
| 性能 | 多次創建 File 對象,字符串拼接開銷 | 僅創建必要 File 對象,較優 |
| 符號鏈接 | 可能誤刪鏈接目標 | 同樣問題,需額外判斷 Files.isSymbolicLink() |
| 推薦場景 | 舊代碼兼容、配置文件讀取路徑 | 新代碼、內部調用、流式處理 |
Files.walkFileTree(最強健)import java.io.IOException;
import java.nio.file.*;
import java.nio.file.attribute.BasicFileAttributes;
public static void deletePath(Path path) throws IOException {
if (!Files.exists(path)) return;
Files.walkFileTree(path, new SimpleFileVisitor() {
@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
Files.delete(file); // 刪除文件
return FileVisitResult.CONTINUE;
}
@Override
public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
if (exc != null) throw exc;
Files.delete(dir); // 刪除空目錄
return FileVisitResult.CONTINUE;
}
});
}
優勢:
FileVisitOption.FOLLOW_LINKS)。Files.deleteIfExists 靜默忽略不存在。FileLock)。Files.isSymbolicLink() 判斷並決定策略。delete() 返回 false,需關閉句柄或重啟進程。public final class FileUtils {
private FileUtils() {}
public static boolean deleteQuietly(Path path) {
try {
deletePath(path);
return true;
} catch (IOException e) {
log.warn("Delete failed: {}", path, e);
return false;
}
}
// 內部使用 NIO.2 實現...
}