Swift清空目录内容
Swift清空目录内容

Swift清空目录内容

Swift需要通过FileManager完成文件系统操作。

删除方式

1、删除整个目录

func deleteDirectory(at url: URL) throws {
    try FileManager.default.removeItem(at: url)
}

2、只清空目录内容

func clearDirectoryContents(at url: URL) throws {
    let fm = FileManager.default
    let items = try fm.contentsOfDirectory(at: url, includingPropertiesForKeys: nil)
    
    for item in items {
        try fm.removeItem(at: item)
    }
}

contentsOfDirectory方法可以获取目录中的文件列表。

例如:

temp/
 ├─ a.txt
 ├─ folder1/
 │   └─ x.png
 └─ folder2/
     └─ y.jpg

contentsOfDirectory得到:

[a.txt, folder1, folder2]

然后调用removeItem方法删除文件和目录中的所有内容。

注意:如果目录内容过大,删除步骤可能会阻塞UI,建议使用后台线程处理删除任务:

func deleteDirectoryAsync(at url: URL) async {
    // Task.detached 后台线程删除文件
    try await Task.detached(priority: .userInitiated) {
        try FileManager.default.removeItem(at: url)
    }
}

3、精细化清空目录内容

如果想要统计删除的内容,并且想要过滤隐藏文件、统计删除失败等场景,可以enumerator方法遍历目录中的所有内容并删除。

static func cleanTempFolder() async -> Bool {
    let tempURL = FileManager.default.temporaryDirectory
    
    // 遍历目录内容
    guard let enumerator = FileManager.default.enumerator(
        at: tempURL,
        includingPropertiesForKeys: [.fileSizeKey, .isRegularFileKey, .isDirectoryKey],
        options: [.skipsHiddenFiles, .skipsPackageDescendants]
    ) else {
        print("无法访问 \(tempURL)")
        return false
    }
    
    // 异步环境中将 enumerator 转换为 Sendable 的 Array 类型
    let allFiles = Array(enumerator)

    var filesToDelete: [(url: URL, size: Int)] = []
    var dirsToDelete: [URL] = []
    
    for case let fileURL as URL in allFiles {
        do {
            let values = try fileURL.resourceValues(forKeys: [.fileSizeKey, .isRegularFileKey, .isDirectoryKey])
            
            if values.isRegularFile == true {
                let size = values.fileSize ?? 0
                filesToDelete.append((url: fileURL,size: size))
            } else if values.isDirectory == true {
                dirsToDelete.append(fileURL)
            }
        } catch {
            print("读取文件大小失败:\(fileURL),错误: \(error)")
        }
    }

    // 在后台线程删除
    return await Task.detached(priority: .userInitiated) {
        var deletedFiles = 0
        var deletedSize = 0
        var failedFiles = 0
        
        // 删除文件
        for (fileURL, size) in filesToDelete {
            do {
                try FileManager.default.removeItem(at: fileURL)
            } catch {
                print("删除文件失败:\(fileURL.path),错误信息:\(error.localizedDescription)")
            }
        }
        
        // 删除目录
        for dirURL in dirsToDelete.reversed() {
            do {
                try FileManager.default.removeItem(at: dirURL)
            } catch {
                print("删除目录失败:\(dirURL.path),错误信息:\(error.localizedDescription)")
            }
        }

        return true
    }.value
}

enumerator 遍历并删除目录内容,也可以进行统计。

目录在这里需要使用 reversed 进行反向删除,原因在于:

temp/
├── folder1/
│   ├── file1.txt
│   └── subfolder/
│       └── file2.txt
└── folder2/
└── file3.txt

假设临时文件结构如上,enumerator 的遍历顺序为:

[
  temp/folder1/,              // 1. 目录
  temp/folder1/file1.txt,     // 2. 文件
  temp/folder1/subfolder/,    // 3. 子目录
  temp/folder1/subfolder/file2.txt,  // 4. 文件
  temp/folder2/,              // 5. 目录
  temp/folder2/file3.txt      // 6. 文件
]

如果正向删除,则无法统计目录中的文件和子目录。

1. 删除 folder1/  // 删除目录、文件和子目录
2. 删除 folder1/subfolder/  // 删除失败,已经在上一步被删除
3. 删除 folder2/  // 删除失败,已经在上一步被删除

反向删除则可以依次删除每一个子文件和子目录:

1. 删除 folder2/  // 删除成功
2. 删除 folder1/subfolder/  // 删除成功
3. 删除 folder1/  // 删除成功,folder1的内容已经为空

总结

清空目录内容操作在面临大量文件的目录时,可能会导致 UI 卡顿,建议使用后台线程处理删除操作。

相关文章

1、Swift 管理文件的FileManager类

   

如果您认为这篇文章给您带来了帮助,您可以在此通过支付宝或者微信打赏网站开发者。

欢迎加入我们的 微信交流群QQ交流群,交流更多精彩内容!
微信交流群二维码 QQ交流群二维码

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注