How to overwrite a file with NSFileManager when copying?

IphoneIosIpadFilesystemsNsfilemanager

Iphone Problem Overview


I'm using this method to copy a file:

[fileManager copyItemAtPath:sourcePath toPath:targetPath error:&error];

I want to overwrite a file when it exists already. The default behavior of this method is to throw an exception/error "File Exists." when the file exists. There's no option to specify that it should overwrite.

So what would be the safest way to do this?

Would I first check if the file exists, then delete it, and then attempt to copy? This has the danger that the app or device goes OFF right in the nanosecond after the file has been deleted but the new file hasn't been copied to that place. Then there's nothing.

Maybe I would have to change the name of the new file first, then delete the old, and then re-change the name of the new? Same problem. What if in this nanosecond the app or device goes OFF and renaming doesn't happen?

Iphone Solutions


Solution 1 - Iphone

If you can't/don't want to keep the file contents in memory but want an atomic rewrite as noted in the other suggestions, you can first copy the original file to a temp directory to a unique path (Apple's documentation suggests using a temporary directory), then use NSFileManager's

-replaceItemAtURL:withItemAtURL:backupItemName:options:resultingItemURL:error:

According to the reference documentation, this method 'replaces the contents of the item at the specified URL in a manner that insures no data loss occurs.' (from reference documentation). The copying of the original to the temporary directory is needed because this method moves the original file. Here's the NSFileManager reference documentation about -replaceItemAtURL:withItemAtURL:backupItemName:options:resultingItemURL:error:

Solution 2 - Iphone

You'd want to do an atomic save in this case, which would be best achieved by using NSData or NSString's writeToFile:atomically: methods (and their variants):

NSData *myData = ...; //fetched from somewhere
[myData writeToFile:targetPath atomically:YES];

Or for an NSString:

NSString *myString = ...;
NSError *err = nil;
[myString writeToFile:targetPath atomically:YES encoding:NSUTF8StringEncoding error:&err];
if(err != nil) {
  //we have an error.
}

Solution 3 - Iphone

If you're not sure if the file exists, this works on swift 3+

try? FileManager.default.removeItem(at: item_destination)
try FileManager.default.copyItem(at: item, to: item_destination)

The first line fails and is ignored if the file doesn't already exist. If there's a exception during the second line, it throws as it should.

Solution 4 - Iphone

Swift4:

_ = try FileManager.default.replaceItemAt(previousItemUrl, withItemAt: currentItemUrl)

Solution 5 - Iphone

Detect file exists error, delete the destination file and copy again.

Sample code in 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
        }
    }
}

Solution 6 - Iphone

For overwriting files, I prefer

NSData *imgDta = UIImageJPEGRepresentation(tImg, 1.0);
    
[imgDta writeToFile:targetPath options:NSDataWritingFileProtectionNone error:&err];

Removing & copying files in loop sometimes doesn't work as intended

Solution 7 - Iphone

I think what you're looking for is the NSFileManagerDelegate protocol method:

- (BOOL)fileManager:(NSFileManager *)fileManager shouldProceedAfterError:(NSError *)error copyingItemAtPath:(NSString *)srcPath toPath:(NSString *)dstPath;

From this method, you can decide what to do with the existing file (rename/delete) and then proceed with the copy.

Solution 8 - Iphone

I think the possibility of the nanosecond you mensioned is feeble. so stick to the first method of removing the existing file and copying the new file.

Solution 9 - Iphone

This is for improvement of 'Swift 3 and above' of question '[Move file and override [duplicate]] 1' which is marked duplicate of this question.

To move file from sourcepath(string) to DestinationPath(string). Delete the existing file if same name file already exists at 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
{
}

Solution 10 - Iphone

The following code ensures that the copy will succeed without file corruption or loss, even if the application is terminated at any time.

if try FileManager.default.fileExists(atPath: target.path) == true {
    try fileManager.replaceItemAt(target, withItemAt: source)
}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionProud MemberView Question on Stackoverflow
Solution 1 - Iphonemz2View Answer on Stackoverflow
Solution 2 - IphoneJacob RelkinView Answer on Stackoverflow
Solution 3 - IphoneAjmal KunnummalView Answer on Stackoverflow
Solution 4 - IphoneSajede NouriView Answer on Stackoverflow
Solution 5 - IphoneTyler LiuView Answer on Stackoverflow
Solution 6 - Iphonenirvana74vView Answer on Stackoverflow
Solution 7 - IphoneataranlenView Answer on Stackoverflow
Solution 8 - IphoneArunGJView Answer on Stackoverflow
Solution 9 - IphoneSHSView Answer on Stackoverflow
Solution 10 - Iphone闪电狮View Answer on Stackoverflow