FileManager — 是 Foundation 框架中的一个类,提供用于操作 iOS、macOS 和其他 Apple 平台文件系统的接口。它可以创建、读取、移动和删除文件及目录,以及管理元数据和访问权限。在 iOS 中,所有 FileManager 操作都受限于应用的沙盒范围。根据 Apple Developer Documentation (2026),FileManager 是线程安全的,可以从后台线程使用,但所有文件系统操作都必须考虑沙盒和 Security-Scoped Bookmarks 访问权限。
要点
FileManager — 是 Foundation 框架中的一个单例类,提供统一的 API 用于在所有 Apple 平台上与文件系统交互。可通过 FileManager.default 或通过创建带有自定义委托的实例来访问。
该类的主要功能包括:检查文件是否存在(fileExists)、创建目录(createDirectory)、复制和移动(copyItem、moveItem)、删除(removeItem)、获取属性(attributesOfItem)和目录内容(contentsOfDirectory)。FileManager 与 NSData、String 和 JSONEncoder/Decoder 紧密相关,用于数据序列化。
FileManager 是线程安全的:Apple 保证从不同线程调用方法的安全性。然而,文件系统操作在处理大文件时可能会很慢,因此 Apple 建议在后台队列(DispatchQueue.global)中执行它们,并调用 FileManagerDelegate 方法来通知进度。
let fileManager = FileManager.default
let documentsURL = fileManager.urls(
for: .documentDirectory,
in: .userDomainMask
).first!
let fileURL = documentsURL.appendingPathComponent("data.plist")
if fileManager.fileExists(atPath: fileURL.path) {
print("File exists at \(fileURL.path)")
}
每个 iOS 应用在沙盒中有三个主要目录可通过 FileManager 访问:Documents、Library 和 tmp。每个目录都有其用途和备份规则,遵守这些规则对于通过 App Store 审核至关重要。
Documents — 用于用户数据,需要在启动之间保留并备份到 iCloud。Library — 用于应用文件:缓存(Caches)、偏好设置(Preferences)、数据库(Application Support)。tmp — 用于临时文件,系统可在应用启动之间的任何时候删除这些文件。
| 目录 | FileManager URL | 备份 | 用途 |
|---|---|---|---|
| Documents | .documentDirectory | 是 | 用户数据、文件、导出 |
| Library/Caches | .cachesDirectory | 否 | 图片缓存、临时数据 |
| Library/Preferences | .libraryDirectory + "/Preferences" | 是 | UserDefaults、应用设置 |
| Library/Application Support | .applicationSupportDirectory | 是 | 数据库、CoreData、Realm |
| tmp | .tmpDirectory (NSTemporaryDirectory) | 否 | 会话临时文件 |
Apple 规则:如果文件可以从互联网恢复或重新创建 — 应存储在 Caches 中(无备份)。如果文件包含用户数据 — 存储在 Documents 中(有备份)。文件放置不正确是应用被拒绝的常见原因之一,因为 Apple 会检查是否符合 Storage & iCloud Backup Guidelines。
FileManager 本身不提供读取文件内容的方法 — 这需要使用 NSData(contentsOf)、String(contentsOf) 或 FileHandle 方法。FileManager 负责文件的管理:检查存在性、移动、复制、删除。
写入数据时使用 createFile(atPath:contents:attributes:) 方法或高级 API — data.write(to:)、JSONEncoder.encode 和 PropertyListEncoder。FileManager 还提供 FileHandle 用于流式读取和写入大文件,而无需将整个文件加载到内存中。
struct UserSettings: Codable {
let username: String
let isDarkMode: Bool
let fontSize: Int
}
let settings = UserSettings(
username: "developer",
isDarkMode: true,
fontSize: 16
)
// 将 JSON 写入 Documents
let encoder = JSONEncoder()
encoder.outputFormatting = .prettyPrinted
let data = try encoder.encode(settings)
let url = documentsURL.appendingPathComponent("settings.json")
try data.write(to: url, options: .atomic)
// 读取 JSON
let loadedData = try Data(contentsOf: url)
let loadedSettings = try JSONDecoder()
.decode(UserSettings.self, from: loadedData)
写入时使用 options: .atomic — 这确保在写入失败时文件不会损坏:数据首先保存到临时文件,然后原子性地移动到目标路径。读取大文件时,使用带有 .readingMode 的 FileHandle,分块读取数据,控制内存使用。
FileManager 提供了完整的目录管理方法:createDirectory(通过 withIntermediateDirectories 创建所有中间文件夹)、contentsOfDirectory(获取文件列表)、enumeratorAt(递归遍历)和 subpathsOfDirectory(目录内的所有路径)。
enumeratorAt 方法返回一个 DirectoryEnumerator,可以高效地遍历大目录而无需将整个内容加载到内存中。它支持通过 skipDescendants 进行过滤,并提供每个元素的属性,而无需额外查询文件系统。
// 递归目录遍历
if let enumerator = fileManager.enumerator(
at: documentsURL,
includingPropertiesForKeys: [.fileSizeKey, .isDirectoryKey]
) {
for case let fileURL as URL in enumerator {
let attrs = try fileURL.resourceValues(
for: [.fileSizeKey, .isDirectoryKey]
)
if attrs.isDirectory == false {
let size = attrs.fileSize ?? 0
print("File: \(fileURL.lastPathComponent), Size: \(size) bytes")
}
}
}
删除目录时使用 removeItem(at:)。注意:在 iOS 中删除目录是不可逆的 — 文件不会像 macOS 那样进入废纸篓。删除前请确保不再使用此目录中的文件,并在后台线程上执行操作,因为删除大量文件可能会阻塞 UI。
FileManager 通过 URLForUbiquityContainerIdentifier 方法与 iCloud Drive 集成,该方法返回应用的 iCloud 目录 URL。使用前需要在项目中启用 iCloud capability 并添加相应的 entitlement。
iCloud 文件会自动同步,但 FileManager 提供了手动控制的方法:startDownloadingUbiquitousItem 强制开始下载,evictUbiquitousItem 删除本地副本,urlOfItem(at:) 返回 iCloud 文件的本地 URL。NSMetadataQuery 用于在 iCloud 中搜索文件。
关键限制:iCloud Drive 不支持 Documents 目录中的文件 — 仅支持 ubiquityContainer 中的文件。不要尝试通过 iCloud 同步 Documents;对于少量数据,请使用 NSUbiquitousKeyValueStore,对于复杂结构,请使用 Core Data 和 CloudKit。
使用 FileManager 的操作可能代价高昂,尤其是在闪存较慢的设备上。Apple 的主要建议包括:在后台队列中执行所有文件操作、尽量减少 fileExistsAtPath 调用次数以及使用结果缓存。
fileExists 方法执行系统调用 stat(),这相对较慢。如果要在读取文件前检查其是否存在,最好直接尝试读取并处理错误 — 这执行相同的 stat,但消除了双重系统调用。对于批量检查,使用带有 resourceValues 的 enumeratorAt。
优化处理大量数据:
Apple Instruments 提供了 File Activity 模板用于分析文件操作。使用它可以识别瓶颈 — 例如,循环中频繁调用 fileExists 或在主线程上的写入操作。最常见的性能问题与在应用最小化时同步写入大文件有关。
常见问题
FileManager — 是 Foundation 框架中用于操作 Apple 文件系统的类。提供用于创建、读取、移动、删除文件和目录的 API。在 iOS 中,其操作受限于应用沙盒范围,Security-Scoped Bookmarks 除外。
Documents — 用户数据,在 iCloud 中有备份。Library/Caches — 无备份的缓存。Library/Application Support — 数据库。tmp — 临时文件。App Group Container — 用于同一组应用之间的共享数据。
调用 FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first。该方法返回包含当前应用沙盒内 Documents 目录绝对路径的 URL。使用 fileExists(atPath:) 检查目录是否存在。
不能,iOS 沙盒禁止访问其他应用的文件系统。例外情况:App Groups(同一开发者应用的共享目录)和 Security-Scoped Bookmarks(通过 UIDocumentPicker 和 iCloud Drive 访问文件)。
写入时使用 .atomic 选项 — 数据首先保存到临时文件,然后原子性地移动到目标路径。这可以防止写入失败时文件损坏。对于大数据,使用 FileHandle 以 1-2 MB 的块进行写入。
总结
我们将开发一款交钥匙移动应用程序
IT Sectr自2017年以来为初创企业和企业打造iOS和Android应用程序。我们将为您提供咨询并提出最佳解决方案。