33

He encontrado esta manera de crear un directorio si no existe. Pero parece un poco inestable y me temo que esto puede salir mal en 1 de cada 1000 intentos.¿Existe alguna manera más segura de crear un directorio si no existe?

if(![[NSFileManager defaultManager] fileExistsAtPath:bundlePath]) { 
    [[NSFileManager defaultManager] createDirectoryAtPath:bundlePath withIntermediateDirectories:YES attributes:nil error:NULL]; 
} 

Sólo existe este incómodo método fileExistsAtPath que también busca archivos y no solo directorios. Pero para mí, lo peligroso es: ¿y si esto sale mal? ¿Qué debo hacer? ¿Cuál es la mejor práctica para garantizar que el directorio se crea y solo se crea cuando no existe?

Sé que las operaciones del sistema de archivos nunca son seguras. El dispositivo podría perder energía de la batería de forma repentina justo en el momento en que comenzó a palear los bits de A a B. O puede tropezar con un bit malo y colgarse por un segundo. Tal vez en raras ocasiones devuelve SÍ incluso si no hay directorio. En pocas palabras: no confío en las operaciones del sistema de archivos.

¿Cómo puedo hacer esto completamente seguro?

Respuesta

66

En realidad se puede saltar el if, a pesar de que docs de Apple dicen que el directorio no debe existir, que sólo es cierto si usted está pasando withIntermediateDirectories:NO

que lo pone abajo a una llamada. El siguiente paso es capturar cualquier error:

NSError * error = nil; 
[[NSFileManager defaultManager] createDirectoryAtPath:bundlePath 
          withIntermediateDirectories:YES 
              attributes:nil 
               error:&error]; 
if (error != nil) { 
    NSLog(@"error creating directory: %@", error); 
    //.. 
} 

Esto hará no producirá un error si el directorio ya existe.

+0

¡Genial! ¿Qué debo hacer si ocurre un error? ¿Tiene sentido intentar e intentar nuevamente? (al menos algunas veces ... ¿y qué pasa si eso no ayuda?) – dontWatchMyProfile

+0

No estoy seguro de qué hacer si hay un error. Depende de lo elegante que quieras obtener. Puede buscar errores específicos y manejarlos de manera diferente, o tratar de crear una ruta diferente. Quizás dejar que el usuario elija uno diferente? –

+5

Necesita verificar el valor de retorno, no el puntero de error – Sven

3
NSFileManager *fileManager= [NSFileManager defaultManager]; 
if(![fileManager fileExistsAtPath:directory isDirectory:&isDir]) 
    if(![fileManager createDirectoryAtPath:directory withIntermediateDirectories:YES attributes:nil error:NULL]) 
     NSLog(@"Error: Create folder failed %@", directory); 

De un tema SO here.

Después de crear un directorio, puede vaciar el sistema de archivos y luego verificar si su directorio creado recientemente existe. Esto es probablemente excesivo, pero nunca se puede tener demasiado exceso.

+0

¿Qué quiere decir por "limpiar el sistema de archivos"? – dontWatchMyProfile

+0

dontWatchMyProfile: las escrituras en un disco (o en este caso, en el almacenamiento FLASH) a menudo se escriben primero en RAM mucho más rápido, y luego se asignan al almacenamiento principal a medida que el rendimiento y la carga lo permiten. Vaciar ese caché, o "sincronizar", ordena al sistema que "escriba todo el contenido del caché en este momento". Esto es importante en caso de que, como dice el OP, se pierda poder. Tengo poca información sobre el archivo IO en el iPhone y los dispositivos relacionados, pero existe un hilo SO con relevancia relevante aquí: http://stackoverflow.com/questions/459537/clear-buffer-cache-on-mac-os-x –

+2

Entre la línea dos y la línea tres, debe agregar un comentario como este: // Aquí, cambiamos los procesos y otra persona puede crear un archivo con el nombre que acabamos de pasar a fileExistsAtPath: isDirectory: - por lo que este cheque no vale realmente obra. –

1

en Swift 2 se parece a esto:

do { 
    try NSFileManager.defaultManager().createDirectoryAtPath(pathURL.absoluteString, withIntermediateDirectories: true, attributes: nil) 
} catch { 
    print(error) 
} 
4

para SWIFT 3,0

do { 
    try FileManager.default.createDirectory(atPath: folder, withIntermediateDirectories: true, attributes: nil) 
} catch { 
    print(error) 
} 
Cuestiones relacionadas