Как переписать файл с NSFileManager при копировании? - PullRequest
46 голосов
/ 26 мая 2011

Я использую этот метод для копирования файла:

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

Я хочу перезаписать файл, когда он уже существует.Поведение по умолчанию этого метода - генерировать исключение / ошибку «Файл существует».когда файл существует.Нет никакой возможности указать, что он должен перезаписывать.

Итак, какой самый безопасный способ сделать это?

Могу ли я сначала проверить, существует ли файл, затем удалить его и затем попытатьсякопировать?Это может привести к тому, что приложение или устройство выключится прямо в наносекунду после удаления файла, но новый файл не будет скопирован в это место.Тогда ничего нет.

Может быть, мне придется сначала изменить имя нового файла, затем удалить старый, а затем повторно изменить имя нового?Та же проблема.Что если в эту наносекунду приложение или устройство выключится и переименование не произойдет?

Ответы [ 9 ]

49 голосов
/ 09 марта 2012

Если вы не можете / не хотите хранить содержимое файла в памяти, но хотите атомарную перезапись, как отмечено в других предложениях, вы можете сначала скопировать исходный файл во временный каталог по уникальному пути (документация Appleпредлагает использовать временный каталог), затем используйте NSFileManager

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

Согласно справочной документации, этот метод «заменяет содержимое элемента по указанному URL-адресу таким образом,происходит потеря данных.(из справочной документации).Копирование оригинала во временный каталог необходимо, поскольку этот метод перемещает исходный файл. Вот справочная документация NSFileManager о -replaceItemAtURL:withItemAtURL:backupItemName:options:resultingItemURL:error:

22 голосов
/ 26 мая 2011

В этом случае вы захотите сделать атомарное сохранение , что лучше всего достигается с помощью методов NSData или NSString * writeToFile:atomically: (и их вариантов):

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

Или для NSString:

NSString *myString = ...;
NSError *err = nil;
[myString writeToFile:targetPath atomically:YES encoding:NSUTF8StringEncoding error:&err];
if(err != nil) {
  //we have an error.
}
6 голосов
/ 04 октября 2015

Обнаружить ошибку файла существует, удалите файл назначения и скопируйте снова.

Пример кода в 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
        }
    }
}
5 голосов
/ 19 сентября 2018

Если вы не уверены, существует ли файл, это работает на swift 3 +

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

Первая строка завершается неудачно и игнорируется, если файл еще не существует. Если во второй строке есть исключение, оно выдается как следует.

4 голосов
/ 06 августа 2014

Для перезаписи файлов я предпочитаю

NSData *imgDta = UIImageJPEGRepresentation(tImg, 1.0);

[imgDta writeToFile:targetPath options:NSDataWritingFileProtectionNone error:&err];

Удаление и копирование файлов в цикле иногда не работает должным образом

3 голосов
/ 03 апреля 2018

Swift4:

_ = try FileManager.default.replaceItemAt(previousItemUrl, withItemAt: currentItemUrl)
1 голос
/ 03 декабря 2014

Я думаю, что вам нужен метод протокола NSFileManagerDelegate:

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

С помощью этого метода вы можете решить, что делать с существующим файлом (переименовать / удалить), а затем продолжить копирование.

1 голос
/ 26 мая 2011

Я думаю, что вероятность наносекунды, которую вы упомянули, слабая. поэтому придерживайтесь первого метода удаления существующего файла и копирования нового файла.

0 голосов
/ 16 апреля 2018

Это для улучшения 'Swift 3 и выше' вопроса ' Переместить файл и переопределить [duplicate] ', который помечен как дубликат этого вопроса.

Чтобы переместить файл из источника(строка) в DestinationPath (строка).Удалите существующий файл, если такой же файл имени уже существует в 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
{
}
...