复制时如何使用NSFileManager覆盖文件?

| 我正在使用此方法复制文件:
[fileManager copyItemAtPath:sourcePath toPath:targetPath error:&error];
我想覆盖一个已经存在的文件。该方法的默认行为是在文件存在时引发异常/错误“文件已存在”。没有选项指定要覆盖。 那么最安全的方法是什么? 我先检查文件是否存在,然后删除它,然后再尝试复制吗?这样做的危险是,删除文件后,应用程序或设备会在十亿分之一秒内关闭,但新文件尚未复制到该位置。然后什么都没有。 也许我必须先更改新文件的名称,然后删除旧文件,然后重新更改新文件的名称?同样的问题。如果在十亿分之一秒内应用程序或设备关闭并且没有重命名怎么办?     
已邀请:
您需要在这种情况下进行原子保存,最好使用
NSData
NSString
\的
writeToFile:atomically:
方法(及其变体)来实现:
NSData *myData = ...; //fetched from somewhere
[myData writeToFile:targetPath atomically:YES];
或for2ѭ:
NSString *myString = ...;
NSError *err = nil;
[myString writeToFile:targetPath atomically:YES encoding:NSUTF8StringEncoding error:&err];
if(err != nil) {
  //we have an error.
}
    
如果您不能/不希望将文件内容保留在内存中,但希望按照其他建议中的说明进行原子重写,则可以先将原始文件复制到临时目录中的唯一路径(Apple \的文档建议使用一个临时目录),然后使用NSFileManager \
-replaceItemAtURL:withItemAtURL:backupItemName:options:resultingItemURL:error:
根据参考文档,此方法“以确保不丢失数据的方式”将项目的内容替换为指定的URL。”(来自参考文档)。需要将原始文件复制到临时目录,因为此方法将移动原始文件。 这是关于ѭ7的NSFileManager参考文档     
检测文件存在错误,删除目标文件并再次复制。 Swift 2.0中的示例代码:
class MainWindowController: NSFileManagerDelegate {

    let fileManager = NSFileManager()

    override func windowDidLoad() {
        super.windowDidLoad()
        fileManager.delegate = self
        do {
            try fileManager.copyItemAtPath(srcPath, toPath: dstPath)
        } catch {
            print(\"File already exists at \\\'\\(srcPath)\\\':\\n\\((error as NSError).description)\")
        }
    }

    func fileManager(fileManager: NSFileManager, shouldProceedAfterError error: NSError, copyingItemAtPath srcPath: String, toPath dstPath: String) -> Bool {
        if error.code == NSFileWriteFileExistsError {
            do {
                try fileManager.removeItemAtPath(dstPath)
                print(\"Existing file deleted.\")
            } catch {
                print(\"Failed to delete existing file:\\n\\((error as NSError).description)\")
            }
            do {
                try fileManager.copyItemAtPath(srcPath, toPath: dstPath)
                print(\"File saved.\")
            } catch {
                print(\"File not saved:\\n\\((error as NSError).description)\")
            }
            return true
        } else {
            return false
        }
    }
}
    
如果您不确定文件是否存在,则可在3+版本上运行
try? FileManager.default.removeItem(at: item_destination)
try FileManager.default.copyItem(at: item, to: item_destination)
第一行失败,如果该文件不存在,则将其忽略。如果第二行出现异常,它将按原样抛出。     
对于覆盖文件,我更喜欢
NSData *imgDta = UIImageJPEGRepresentation(tImg, 1.0);

[imgDta writeToFile:targetPath options:NSDataWritingFileProtectionNone error:&err];
循环中删除和复制文件有时无法正常工作     
Swift4:
_ = try FileManager.default.replaceItemAt(previousItemUrl, withItemAt: currentItemUrl)
    
我认为您提到的纳秒级可能性很小。因此,请坚持删除现有文件并复制新文件的第一种方法。     
我认为您正在寻找的是NSFileManagerDelegate协议方法:
- (BOOL)fileManager:(NSFileManager *)fileManager shouldProceedAfterError:(NSError *)error copyingItemAtPath:(NSString *)srcPath toPath:(NSString *)dstPath;
通过这种方法,您可以决定如何处理现有文件(重命名/删除),然后继续进行复制。     
这是为了改进问题“移动文件并覆盖[重复]”的“快速3及更高版本”,标记为该问题的重复项。 将文件从sourcepath(string)移到DestinationPath(string)。 如果DestinationPath中已经存在相同名称的文件,请删除现有文件。
// Set the correct path in string in \'let\' variables.
let destinationStringPath = \"\"
let sourceStringPath = \"\"

let fileManager:FileManager = FileManager.default
do
{
    try fileManager.removeItem(atPath: sourceStringPath)
}
catch
{
}

do
{
    try fileManager.moveItem(atPath: sourceStringPath, toPath: destinationStringPath)
}
catch
{
}
    

要回复问题请先登录注册