Swift中替换同名文件时重命名Documents目录文件的现代方法
Swift中替换Documents目录已有文件的重命名方法问题
需要替换目标名称已存在的文件时,在Swift中重命名Documents目录文件的现代方法是什么?(因此选择replaceItem相关方法而非moveItem系列方法)
尝试过不少旧方案但都无效,具体情况如下:
尝试的Swift代码(无报错但文件消失)
let oldpicname = "22_contactpic.png" let newpicname = "9213_contactpic.png" do { let path = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0] let documentDirectory = URL(fileURLWithPath: path) let originPath = documentDirectory.appendingPathComponent(oldpicname) let destinationPath = documentDirectory.appendingPathComponent(newpicname) print("try to replace file") try FileManager.default.replaceItemAt(originPath, withItemAt: destinationPath) } catch { print("FIRST TRY FAILED TO RENAME FILE") print(error) }
这段代码编译通过且无报错,但执行后目标文件不存在。
参考代码的问题
曾看到一段建议代码:
var rv = URLResourceValues() rv.name = newname try? url.setResourceValues(rv)
但运行时出现「无法对不可变值使用可变成员」等错误。
可用的Objective-C实现
目前能用Objective-C完成该功能,代码如下:
- (void)renameWithReplaceFileWithName:(NSString *)beforeName toName:(NSString *)afterName { NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); NSString *documentsDirectory = [paths objectAtIndex:0]; NSString *filePathBefore = [documentsDirectory stringByAppendingPathComponent:beforeName]; NSString *filePathAfter = [documentsDirectory stringByAppendingPathComponent:afterName]; NSLog(@"filepath after is%@. This will be the new name of this file",filePathAfter); NSFileManager *manager = [NSFileManager defaultManager]; if ([manager fileExistsAtPath:filePathBefore]) { NSError *error = nil; NSURL *previousItemUrl = [NSURL fileURLWithPath: filePathBefore]; NSURL *currentItemUrl = [NSURL fileURLWithPath:filePathAfter]; [[NSFileManager defaultManager] replaceItemAtURL:previousItemUrl withItemAtURL:currentItemUrl backupItemName:nil options:0 resultingItemURL:nil error:&error]; if (error) { // handle error } } }
解决建议
方法1:用moveItem带替换选项(推荐)
重命名并覆盖已有目标文件,最直接的方式是使用FileManager的moveItem(at:to:),并通过错误处理兼容目标文件已存在的场景:
let oldFileName = "22_contactpic.png" let newFileName = "9213_contactpic.png" do { // 现代方式获取Documents目录URL let documentsDir = try FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: false) let oldURL = documentsDir.appendingPathComponent(oldFileName) let newURL = documentsDir.appendingPathComponent(newFileName) guard FileManager.default.fileExists(atPath: oldURL.path) else { print("旧文件不存在") return } // 尝试直接移动,若目标文件存在则触发错误分支 try FileManager.default.moveItem(at: oldURL, to: newURL) } catch let error as NSError { // 目标文件已存在,使用文件管理器的替换选项重新执行 if error.code == NSFileWriteFileExistsError { do { let documentsDir = try FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: false) let oldURL = documentsDir.appendingPathComponent(oldFileName) let newURL = documentsDir.appendingPathComponent(newFileName) try FileManager.default.moveItem(at: oldURL, to: newURL) } catch { print("重命名失败: \(error.localizedDescription)") } } else { print("重命名失败: \(error.localizedDescription)") } }
方法2:修正URLResourceValues用法
之前的错误是因为url被声明为不可变的let,需要改为var才能修改资源属性:
let oldFileName = "22_contactpic.png" let newFileName = "9213_contactpic.png" do { let documentsDir = try FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: false) // 声明为var,允许修改资源属性 var fileURL = documentsDir.appendingPathComponent(oldFileName) guard FileManager.default.fileExists(atPath: fileURL.path) else { print("旧文件不存在") return } var resourceValues = URLResourceValues() resourceValues.name = newFileName try fileURL.setResourceValues(resourceValues) } catch { print("修改文件名失败: \(error.localizedDescription)") }
注意:如果目标文件已存在,此方法会报错,需提前判断并删除目标文件,或结合replaceItem处理。
方法3:正确使用replaceItem实现替换+重命名
replaceItem(at:withItemAt:)的逻辑是用第二个URL的文件替换第一个URL的文件,替换后第二个URL的文件会被删除。如果需要用旧文件覆盖已存在的新文件并完成重命名,可按以下逻辑编写:
let oldFileName = "22_contactpic.png" let newFileName = "9213_contactpic.png" do { let documentsDir = try FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: false) let oldURL = documentsDir.appendingPathComponent(oldFileName) let newURL = documentsDir.appendingPathComponent(newFileName) guard FileManager.default.fileExists(atPath: oldURL.path) else { print("旧文件不存在") return } if FileManager.default.fileExists(atPath: newURL.path) { // 新文件已存在,用旧文件替换它 try FileManager.default.replaceItem(at: newURL, withItemAt: oldURL) } else { // 新文件不存在,直接重命名 try FileManager.default.moveItem(at: oldURL, to: newURL) } } catch { print("操作失败: \(error.localizedDescription)") }
内容的提问来源于stack exchange,提问作者user6631314
相关产品推荐
相关产品推荐

