2011-04-18 34 views
11

Tenemos un método MoveFile que generalmente funciona, pero sigue fallando en el sitio de un cliente.File.Move falla cuando está precedido por un archivo. Eliminar

if (File.Exists(target)) 
{ 
    File.Delete(target); 
} 

File.Move(source, target); 

La llamada a File.Move falla repetidamente con

System.IO.IOException: Cannot create a file when that file already exists. 

    at System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath) 
    at System.IO.__Error.WinIOError() 
    at System.IO.File.Move(String sourceFileName, String destFileName) 

Tenemos el control de errores que rodea llamada a ese método, pero no podemos entender por qué File.Delete no está funcionando y no es tirando cualquier cosa

Pensamos en el permiso de archivo, pero el File.Delete habría arrojado un UnauthorizedAccessException.

¿Hay alguna otra razón que haría que File.Move fallara con un "archivo ya existente" cuando va precedido por la eliminación de ese archivo específico?

+0

Curioso: ¿qué sucede si ajusta su File.Move en un if similar (File.Exists (..))? – razlebe

+1

Una posible razón por la que Move to fail after Delete es que aún se puede abrir el manejador de archivo en algún proceso del sistema, por ejemplo, el antivirus o los indexadores de búsqueda. Como la sección de comentarios de File.Delete indica claramente que "Nota de plataforma de Windows NT 4.0: Delete no elimina un archivo abierto para E/S normal o un archivo mapeado en memoria", en su lugar solo marca como Eliminar y otras llamadas dan acceso denegado excepción. – kiran

Respuesta

11

¿Se puede invertir la lógica?

File.Copy (source, target, true) 

para sobrescribir el objetivo continuación

File.Delete(source) 
+0

buena idea :) +1 –

+0

Muy bien, esto fue probado y funciona. Gracias, perdón por la demora en aceptar la respuesta, no es fácil probar algo como esto cuando dependes de un acceso de TeamViewer para implementar una aplicación en el sitio del cliente. –

+0

¡Conozco la sensación! Probablemente debería señalar (si no es deslumbrantemente obvio) que existe una desventaja si el archivo es grande: un movimiento de archivo será bastante rápido si el origen y el destino están en el mismo disco, mientras que la copia de datos potencialmente tomará algun tiempo. Pero en archivos más pequeños, la diferencia de velocidad será insignificante. – MarcE

4

En el pasado, he encontrado que el sistema tiende a eliminar el archivo "más lento" que se está ejecutando su programa.

Lo ideal es comprobar si el archivo se ha eliminado antes de intentar mover un archivo a su lugar. Por lo general, puedes evitar esto con un simple Thread.Sleep (200) o similar, ¡pero probablemente no sea la manera más confiable!

+1

Una manera un poco más confiable basada en esto sería sondear la existencia del archivo en un bucle con un 'Thread.Sleep' y esperar a que se elimine, hasta un cierto tiempo máximo de espera. – devios1

+0

Es una condición de carrera inevitable. Reintentar repetidamente es la única forma de hacerlo. – Tergiver

+2

¿Quizás use un FileSystemWatcher en lugar de un Thread.Sleep? – razlebe

4

Creo que esto puede suceder si alguien más tiene el archivo abierto con la opción FileShare.Delete (es decir, permite la eliminación). En tal caso, el archivo se marcará para su eliminación, pero no se eliminará hasta que se cierre el otro.

No estoy seguro de qué procesos podrían tener un archivo abierto de esa manera, el software antivirus sería una posibilidad.

3

creo que podría obtener mejores resultados de:

System.IO.File.Copy(sourceFileName, destFileName, overwrite); 

modo que overwrite = true

Esto sobrescribirá el archivo antiguo si es que existe en lugar de preocuparse con eliminarlo por separado.

Puede eliminar el original según sea necesario.

0

Aquí está una manera aún mejor que evite la copia o el sondeo del borrado ---
Supongamos que tenemos File_A y File_B. Queremos mover File_B sobre File_A.
Pasos:
1) Cambie el nombre (mueva) File_A a un tercer nombre, File_C.
2) Eliminar archivo_C.
3) Cambie el nombre (mueva) File_B a File_A.

File.Move("File_A", "File_C"); 
File.Delete("File_C"); 
File.Move("File_B", "File_A"); 

Esto elimina la condición de carrera en el que el archivo original se elimina cuelga alrededor mientras que el nuevo archivo se mueve al archivo original.

Cuestiones relacionadas