Estoy usando este método para copiar un archivo:

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

Me desea sobrescribir un archivo cuando ya existe. El comportamiento por defecto de este método es lanzar una excepción/error de «el Archivo Existe.» cuando existe el archivo. No hay ninguna opción para especificar que se debe sobrescribir.

Entonces, ¿cuál sería la forma más segura de hacer esto?

Iba yo primero comprobar si existe el archivo, a continuación, eliminarlo y, a continuación, intente copiar? Esto tiene el peligro de que la aplicación o el dispositivo sale a la derecha en la milésima de segundo después de que el archivo ha sido eliminado, pero el nuevo archivo no ha sido copiado a ese lugar. Entonces no hay nada.

Tal vez tendría que cambiar el nombre del nuevo archivo en primer lugar, a continuación, eliminar el antiguo y, a continuación, volver a cambiar el nombre de la nueva? Mismo problema. Lo que si en este nanosegundo la aplicación o el dispositivo se APAGA y el cambio de nombre no suceda?

InformationsquelleAutor Proud Member | 2011-05-26

9 Comentarios

  1. 22

    Que quieras hacer un atómica guardar en este caso, lo que se logra mejor mediante el uso de NSData o NSString‘s writeToFile:atomically: métodos (y sus variantes):

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

    O para un NSString:

    NSString *myString = ...;
    NSError *err = nil;
    [myString writeToFile:targetPath atomically:YES encoding:NSUTF8StringEncoding error:&err];
    if(err != nil) {
      //we have an error.
    }
    • ¿Cómo funciona esta cosa de trabajar internamente?
    • ¿Qué pasa si usted no desea cargar el archivo completo en la memoria RAM (debido a que es grande)? Carga el archivo parece que podría ser algo ineficiente.
    • Que puede uso NSFileManager‘s -moveItemAtPath:toPath:error: método.
    • Este método no reemplaza los archivos existentes por lo que no puede ser utilizado.
    • De acuerdo, pero es atómica?
  2. 48

    Si usted no puede/no quiere guardar el contenido del archivo en la memoria, pero quiero atómica reescribir como se observó en las otras sugerencias, en primer lugar, puede copiar el archivo original a un directorio temporal para un único camino (la documentación de Apple sugiere el uso de un directorio temporal), a continuación, utilizar NSFileManager del

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

    De acuerdo a la documentación de referencia, este método reemplaza el contenido del elemento en la dirección URL especificada en una manera que asegura que no se produce pérdida de datos.’ (a partir de la documentación de referencia). La copia de la original en el directorio temporal es necesario debido a que este método mueve el archivo original.
    Aquí está el NSFileManager documentación de referencia sobre el -replaceItemAtURL:withItemAtURL:backupItemName:opciones:resultingItemURL:error:

    • Gran respuesta. Upvoted. ¿Y si el archivo es el mismo tiempo de ser procesada de alguna manera, como ser enviados a otra aplicación a través de un UIDocumentInteractionController, o ser impreso a través de AirPrint, o de ser subido a un servidor? Hace esto, asegúrese de que la segunda aplicación (o la impresora o el servidor) obtendrá el archivo nuevo o el viejo, en lugar de un archivo dañado que consta de una serie de bits del archivo nuevo y algunos trozos de la antigua? O es que la suposición de que no es seguro hacer?
    • este método le da garantías de que el archivo que aparece en el destino ubicación es colocado allí de forma atómica. Estoy suponiendo que concurrente de las modificaciones a la fuente datos sitll conducir a la corrupción. Si que es una preocupación, usted probablemente debería envolver las operaciones en el archivo de origen a través de NSFileCoordinator / NSFilePresenter Api – al menos en iOS no debe ser conseguir modificaciones del sistema que no son NSFileCoordinator prueba.
    • Estoy hablando acerca de los cambios en el destino, no la fuente. Entiendo atomicidad wrt para (por ejemplo) el sistema de perder el poder, pero lo que si usted tiene un identificador de archivo / stream abrir el archivo de destino? ¿Cómo atomicidad afectar eso? Decir que estaban cargando «un.pdf» a un servidor, y a mitad de camino a través de la carga, el archivo se reemplaza por «b.pdf». Será el servidor tiene una.pdf, b.pdf o un archivo corrupto? Del mismo modo para imprimir o compartir en otra aplicación. Si la respuesta es que va a ser corruptos, se debe envolver todas las operaciones en el destino en el archivo de la coordinación?
    • Estoy bastante seguro de que esto funciona, al menos en HFS+ reemplazando el inodo en el sistema de archivos, que probablemente significa que el intento de escribir a los identificadores de archivos que estaban abiertos hasta que el inodo de reemplazo sucedió comenzaría su defecto en el archivo de la escritura de las llamadas del sistema (< supongo). Uploads sería un perfecto caso de querer operaciones atómicas de archivos debido a que usted no desea cargar en su lugar en la final de la URL de un archivo que nunca puede terminar de cargar correctamente. También, como no hay ningún sistema de ficheros de la instalación de cierre, archivo de la coordinación es de hecho un programa muy útil, cosa a menudo cuando usted tiene el potencial para varios escritores.
  3. 6

    Detectar el archivo existe error, elimine el archivo de destino y copiar de nuevo.

    Código de ejemplo en 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
            }
        }
    }
    • En Swift 2.0, la mejor opción sería el uso de la do/try/catch sintaxis en lugar de «intentar!» y utilizando el delegado.
  4. 5

    Si usted no está seguro de si el archivo existe, esto funciona en swift 3+

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

    La primera línea de falla y se ignora si el archivo ya no existe. Si hay una excepción durante la segunda línea, se produce como debería.

  5. 4

    Para sobrescribir los archivos, yo prefiero

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

    La eliminación de & copia de los archivos en bucle a veces no funcionan como se pretende

  6. 3

    Swift4:

    _ = try FileManager.default.replaceItemAt(previousItemUrl, withItemAt: currentItemUrl)
    • Mientras que este código puede responder a la pregunta, proporcionar contexto adicional sobre como y/o porque en que se resuelve el problema podría mejorar la respuesta del valor a largo plazo.
  7. 1

    Creo que la posibilidad de los nanosegundos que mensioned es débil. así que mantente en el primer método de extracción del archivo existente y copiar el nuevo archivo.

    • Creo que nanosegundo es dependiente del tamaño de los datos que se escriben en el disco 😉
    • ya están a la derecha. yo estaba considerando sólo los archivos de texto.
  8. 1

    Creo que lo que estás buscando es la NSFileManagerDelegate método de protocolo:

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

    De este método, usted puede decidir qué hacer con el archivo existente (cambiar nombre/borrar) y, a continuación, proceder con la copia.

  9. 0

    Esto es para el mejoramiento de la ‘Swift 3 y por encima’ de la pregunta ‘Mover el archivo y reemplazar [duplicar]‘, que está marcado duplicado de esta pregunta.

    A mover archivo de sourcepath(string) para DestinationPath(cadena).
    Eliminar el archivo existente si es el mismo nombre de archivo que ya existe en 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
    {
    }

Dejar respuesta

Please enter your comment!
Please enter your name here