2009-07-20 11 views
12

Estoy supervisando una carpeta para nuevos archivos y necesito procesarlos. El problema es que ocasionalmente falla la apertura del archivo, porque el sistema no ha terminado de copiarlo.Cómo comprobar si un archivo está completamente copiado en .NET

¿Cuál es la forma correcta de comprobar si el archivo ha terminado de copiarse?

Aclaración: No tengo permisos de escritura para la carpeta/archivos y no puedo controlar el proceso de copiado (es el usuario).

+0

¡Buena pregunta! Cuando tuve ese problema, acabo de agregar System.Threading.Thread.Sleep (1000), pero me encantaría * obtener una mejor solución (Es tan poco convincente ...) – Treb

+0

¿Tiene acceso de lectura al archivo original? que se está copiando? –

Respuesta

11

Creo que la única manera segura de hacerlo es intentando abrir el archivo exclusivamente y capturar una excepción específica.Normalmente odio uso de excepciones para la lógica de aplicación normal, pero me temo que para este escenario no hay otra manera (por lo menos no he encontrado uno todavía):

public bool FileIsDone(string path) 
{ 
    try 
    { 
    using (File.Open(path, FileMode.Open, FileAccess.Read, FileShare.None)) 
    { 
    } 
    } 
    catch(UnauthorizedAccessException) 
    { 
    return false; 
    } 

    return true; 
} 
0

Un enfoque que tomo siempre es crear un archivo al final de mi copia/transferencia llamada "token.txt" sin contenido. La idea es que este archivo se cree justo al final de la operación de transferencia, por lo que puede supervisar la creación de este archivo y cuando se crea este archivo, comienza a trabajar con sus archivos. No olvide borrar este archivo token siempre cuando comience a procesar sus archivos.

+1

Pero si la cuenta de usuario no tiene derecho a eliminar archivos en el servidor, entonces este enfoque no sería útil. – rahul

+2

No piense que la extropía está esperando un proceso de copia que él mismo controle. Entonces, no habría ningún archivo token, ¿verdad? – peSHIr

+1

Creo que no puede decir si tiene o no acceso/control sin un proceso sin más detalles. Es como una lluvia de ideas donde todos dan sus aportes. –

0

También debe cubrir casos como: archivo está en uso por otro programa, se eliminó el archivo (copia no tuvo éxito), etc ..

Utilice un manejo para cubrir todos los casos importantes que podrían ocurrir excepción extendida.

2

No estoy seguro acerca de "la forma correcta", pero podría usar la herramienta de supervisión (FileSystemWatcher supongo) para llenar una cola interna que utiliza para el procesamiento diferido. O mejor aún: solo use una cola para colocar los archivos en los que falló la apertura, para que pueda volver a intentarlos más tarde.

1

Si está utilizando FileSystemWatcher no creo que haya una solución robusta a este problema. Un enfoque sería try/catch/retry más tarde.

0

Depende, un ciclo de reintento es probablemente lo mejor que puede hacer, si no tiene control sobre el proceso de copia.

Si usted tiene control:

  • Si la carpeta es local, se puede exigir que la gente que escribe cosas en que bloquear el archivo para acceso exclusivo, y sólo quite el bloqueo cuando se hacen (que Creo que es el predeterminado para File.Copy). En el lado .Net podría tener un simple ciclo de reintento, con un período de enfriamiento.
    • Como alternativa, puede escribir el archivo en una carpeta temporal y solo después de moverlo al directorio de destino. Esto reduce la ventana donde cosas malas puede suceder (pero no lo elimina)
  • Si la carpeta es un recurso compartido SMB, existe la posibilidad de LockFile ni siquiera funciona (algunas implementaciones Linux). En ese caso, el enfoque común es tener una especie de archivo de bloqueo, que se elimina una vez que la persona que crea el archivo está lista. El problema con el enfoque de archivo de bloqueo es que si se olvida de eliminarlo puede tener problemas.
  • Como consecuencia de estas complicaciones, recomendaría que recibir los datos a través de un servicio WCF o un servicio web puede ser una ventaja, ya que tiene un control mucho mejor.
0

De hecho, para evitar las condiciones de carrera, las La única solución segura es reintentar.

Si haces algo como:

while (file is locked) 
    no-op() 
process file() 

Corre el riesgo de otro proceso salta entre la guardia de tiempo y el estado de archivo de proceso. No importa cómo se implemente su "espera de disponibilidad de archivos", a menos que pueda asegurarse de que el desbloqueo posterior sea el primer proceso para acceder a él, es posible que no sea ese primer usuario.

Esto es más probable que pueda parecer a primera vista, en particular si varias personas miran el archivo, y en particular si están utilizando algo así como el vigilante del sistema de archivos. Por supuesto, aún no es particularmente probable incluso entonces ...

0

¿Los archivos son grandes?

¿Tal vez podría tratar de calcular la suma de comprobación md5 en el archivo?

Si coloca el hash md5 en el nombre del archivo, puede recuperarlo e intentar volver a calcular la suma de comprobación en el archivo. Cuando el md5 es una coincidencia, puede suponer que el archivo ha finalizado.

byte[] md5Hash = null; 
MD5 md5 = new MD5CryptoServiceProvider(); 
using (FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read)) 
    md5Hash = md5.ComputeHash(fs); 

StringBuilder hex = new StringBuilder(); 
foreach (byte b in md5Hash) 
    hex.Append(b.ToString("x2")); 
0

Aquí hay un bucle de vb.net que uso. Espera 2 segundos entre cada comprobación.

Dim donotcopy As Boolean = True 
While donotcopy = True 
    Dim myFile As New FileInfo("Filetocopy") 
    Dim sizeInBytes As Long = myFile.Length 
    Thread.Sleep(2000) 
    Dim myFile2 As New FileInfo("Filetocopy") 
    Dim sizeInBytes2 As Long = myFile2.Length 
    If sizeInBytes2 = sizeInBytes Then donotcopy = False 
End While 
Cuestiones relacionadas