file.delete() 僅能刪除單一檔案或空目錄,非空目錄刪除失敗回傳 false,需遞迴刪除子檔案/子目錄。
public static boolean deleteRecursively(File fileOrDirectory) {
if (fileOrDirectory == null || !fileOrDirectory.exists()) return true;
if (fileOrDirectory.isDirectory()) {
File[] children = fileOrDirectory.listFiles();
if (children != null) {
for (File child : children) {
if (!deleteRecursively(child)) return false;
}
}
}
return fileOrDirectory.delete(); // 刪除空目錄或檔案
}
public void deleteSdCardFolder(String path) {
// 1. 檢查權限 (Android 10+ 範圍儲存需 MediaStore 或 SAF)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
// 建議使用 MediaStore API 或 Storage Access Framework
// 此處僅示範傳統方式
}
// 2. 背景執行緒執行(避免 ANR)
Executors.newSingleThreadExecutor().execute(() -> {
File dir = new File(path);
boolean success = deleteRecursively(dir);
runOnUiThread(() -> Toast.makeText(this,
success ? "刪除成功" : "刪除失敗", Toast.LENGTH_SHORT).show());
});
}
| 版本 | 儲存模型 | 刪除方式 |
|---|---|---|
| < Android 10 (Q) | 傳統檔案系統 | File.delete() + 權限 WRITE_EXTERNAL_STORAGE |
| Android 10 (Q) | 範圍儲存 | 僅能刪除自建檔案;他建檔案需 MediaStore + 用戶確認 |
| Android 11+ (R) | 強制範圍儲存 | 同 Q,MANAGE_EXTERNAL_STORAGE 權限極難獲取 |
// 刪除自建媒體檔案
ContentResolver resolver = getContentResolver();
Uri uri = MediaStore.Files.getContentUri("external");
String selection = MediaStore.MediaColumns.DATA + " LIKE ?";
String[] args = new String[] { path + "%" };
int deleted = resolver.delete(uri, selection, args);
listFiles() 回傳 null:權限不足或非目錄時回傳 null,需防禦性判斷。File API 逐步受限,拥抱 MediaStore/StorageManager/SAF。檔案刪除看似簡單,實則涉及權限模型演進、執行緒調度、遞迴邏輯正確性,需根據目標 API 級別選擇正確方案。