Swift中FileManager.default.url无法创建文件报错的问题排查
Swift本地文件存储与加载问题解决
原实现代码
保存函数
func locallySave(_ data: Data?, for utility: Utility) throws { var fileURL = try FileManager.default.url(for: .applicationSupportDirectory, in: .userDomainMask, appropriateFor: nil, create: true) fileURL.appendPathComponent(Constants.appShortName) fileURL.appendPathComponent("\(utility).json") do { try data?.write(to: fileURL) } catch { print("Error: \(error)") throw error } }
加载函数
func locallyLoad(_ utility: Utility) throws -> Data? { var fileURL = try FileManager.default.url(for: .applicationSupportDirectory, in: .userDomainMask, appropriateFor: nil, create: false) fileURL.appendPathComponent(Constants.appShortName) fileURL.appendPathComponent("\(utility).json") do { let data = try Data(contentsOf: fileURL) return data } catch { print("Error: \(error)") throw error } }
问题说明
当前遇到的核心问题:
- 保存函数设置
create: true后,仍未自动创建所需的子目录及文件,实际路径无内容,报错NSUnderlyingError=0x600000fb0480 {Error Domain=NSPOSIXErrorDomain Code=2 "No such file or directory"} - 怀疑模拟器中每次运行应用的目录变化导致读取失败,但调试时两函数生成的
fileURL完全一致
修复与优化方案
1. 自动创建缺失的目录
url(for:in:appropriateFor:create:)的create: true仅会创建顶层的.applicationSupportDirectory,不会自动创建后续追加的子目录(即Constants.appShortName对应的文件夹)。需手动添加目录创建逻辑:
修改后的保存函数:
func locallySave(_ data: Data?, for utility: Utility) throws { guard let data = data else { return } // 空数据直接返回,避免无意义操作 var fileURL = try FileManager.default.url(for: .applicationSupportDirectory, in: .userDomainMask, appropriateFor: nil, create: true) fileURL.appendPathComponent(Constants.appShortName) // 创建子目录(含中间目录,确保路径上所有缺失的文件夹都被创建) try FileManager.default.createDirectory(at: fileURL, withIntermediateDirectories: true) fileURL.appendPathComponent("\(utility).json") try data.write(to: fileURL) }
2. 解决模拟器目录一致性误解
模拟器中applicationSupportDirectory的路径不会随每次运行变化——路径的唯一标识是应用的Bundle ID,只要Bundle ID不变,目录就固定。之前的读取失败本质还是目录未创建导致的,而非路径变化。
可以在加载函数中添加文件存在判断,做更友好的容错处理:
func locallyLoad(_ utility: Utility) throws -> Data? { var fileURL = try FileManager.default.url(for: .applicationSupportDirectory, in: .userDomainMask, appropriateFor: nil, create: false) fileURL.appendPathComponent(Constants.appShortName) fileURL.appendPathComponent("\(utility).json") // 先判断文件是否存在,不存在直接返回nil guard FileManager.default.fileExists(atPath: fileURL.path) else { return nil } return try Data(contentsOf: fileURL) }
3. 提取公共路径逻辑(可选优化)
为避免重复代码,可将路径构建逻辑提取为私有方法:
private func fileURL(for utility: Utility) throws -> URL { var fileURL = try FileManager.default.url(for: .applicationSupportDirectory, in: .userDomainMask, appropriateFor: nil, create: true) fileURL.appendPathComponent(Constants.appShortName) try FileManager.default.createDirectory(at: fileURL, withIntermediateDirectories: true) fileURL.appendPathComponent("\(utility).json") return fileURL }
简化后的保存与加载函数:
func locallySave(_ data: Data?, for utility: Utility) throws { guard let data = data else { return } try data.write(to: fileURL(for: utility)) } func locallyLoad(_ utility: Utility) throws -> Data? { let url = try fileURL(for: utility) guard FileManager.default.fileExists(atPath: url.path) else { return nil } return try Data(contentsOf: url) }
内容的提问来源于stack exchange,提问作者Tiny Tim
相关产品推荐
相关产品推荐

