Swift中给FileWrapper添加Images文件夹且保存不丢失内容的实现问题
问题根因
- 你当前
fileWrapper方法每次保存都会生成全新的空目录作为MYFImages文件夹,系统收到返回的FileWrapper后会直接用这个新目录覆盖原有的整个文档包,之前存储的所有图片、子文件夹自然会被清空。 - 你直接绕过FileDocument的管理用FileManager写入文档包路径的逻辑有问题:FileWrapper的快照机制不会感知到你手动写入的文件,保存时不会主动保留这部分内容。
- 原有循环逻辑错误:每次循环复用同一个
imageSubFolder实例,最终只会保留最后一个子文件夹。
修复方案
1. 调整MyProject结构,保留已有图片目录快照
新增属性存储读取到的图片目录FileWrapper,避免每次保存都新建空目录。
2. 修改读写逻辑,复用已有目录结构
读取文档时同步保存图片目录结构,写入时只新增缺失的子文件夹,不修改已有内容。
3. 修正图片写入逻辑
所有文档包内的修改都要同步到持有的FileWrapper实例上,保证保存时全量包含所有文件。
完整修改后代码
import UniformTypeIdentifiers struct MyProject: FileDocument { var myFile: MyFile // 新增:存储已有图片目录的快照 var imageDirectoryWrapper: FileWrapper? static var readableContentTypes: [UTType] { [.myf] } init(myFile: MyFile = MyFile()) { self.myFile = myFile } init(configuration: ReadConfiguration) throws { let decoder = JSONDecoder() guard let rootWrappers = configuration.file.fileWrappers, let data = rootWrappers["MYFProject"]?.regularFileContents else { throw CocoaError(.fileReadCorruptFile) } do { self.myFile = try decoder.decode(MyFile.self, from: data) // 读取已有的图片目录保存 self.imageDirectoryWrapper = rootWrappers["MYFImages"] } catch { throw error } } func fileWrapper(configuration: WriteConfiguration) throws -> FileWrapper { let encoder = JSONEncoder() do { let data = try encoder.encode(myFile) let mainDirectory = FileWrapper(directoryWithFileWrappers: [:]) // 配置自定义数据文件 let myfWrapper = FileWrapper(regularFileWithContents: data) myfWrapper.preferredFilename = "MYFProject" mainDirectory.addFileWrapper(myfWrapper) // 复用已有图片目录,不存在才新建 let imagesWrapper = imageDirectoryWrapper ?? FileWrapper(directoryWithFileWrappers: [:]) imagesWrapper.preferredFilename = "MYFImages" // 仅新增不存在的子文件夹,不修改已有内容 let existingSubFolders = Set(imagesWrapper.fileWrappers?.keys ?? []) for numberString in myFile.numbers where !existingSubFolders.contains(numberString) { // 每次新建子文件夹实例,不要复用 let newSubFolder = FileWrapper(directoryWithFileWrappers: [:]) newSubFolder.preferredFilename = numberString imagesWrapper.addFileWrapper(newSubFolder) } mainDirectory.addFileWrapper(imagesWrapper) // 更新存储的快照,供下次保存复用 self.imageDirectoryWrapper = imagesWrapper return mainDirectory } catch { throw error } } // 新增:官方推荐的图片写入方法,同步更新FileWrapper快照 func addImage(_ imageData: Data, subFolderName: String, imageFileName: String) throws { guard let imagesWrapper = imageDirectoryWrapper, let subFolder = imagesWrapper.fileWrappers?[subFolderName] else { throw NSError(domain: "MyProject", code: -1, userInfo: [NSLocalizedDescriptionKey: "目标子文件夹不存在"]) } let imageWrapper = FileWrapper(regularFileWithContents: imageData) imageWrapper.preferredFilename = imageFileName subFolder.addFileWrapper(imageWrapper) } }
注意事项
- 如果要保留原有直接用FileManager写入的逻辑,每次写入完成后需要重新读取整个MYFImages目录更新
imageDirectoryWrapper属性,否则保存时还是会丢失手动写入的文件。 - FileDocument的保存机制是用返回的FileWrapper全量替换整个文档包,所有需要保留的文件必须都包含在返回的目录结构中。
内容的提问来源于stack exchange,提问作者John
相关产品推荐
相关产品推荐

