.net - manager - dokan windows
Archivos de supervisión: cómo saber cuándo se completa un archivo (9)
Tenemos varias aplicaciones .NET que monitorean un directorio para nuevos archivos, usando FileSystemWatcher. Los archivos se copian desde otra ubicación, se cargan a través de FTP, etc. Cuando entran, los archivos se procesan de una forma u otra. Sin embargo, un problema para el que nunca he visto una respuesta satisfactoria es el siguiente: para archivos grandes, ¿cómo sabe uno cuándo se siguen escribiendo los archivos que se monitorean? Obviamente, debemos esperar hasta que los archivos estén completos y cerrados antes de que comencemos a procesarlos. Los argumentos del evento en los eventos de FileSystemWatcher no parecen abordar esto.
¿Has intentado obtener un bloqueo de escritura en el archivo? Si está siendo escrito, eso debería fallar, y tú sabes dejarlo en paz un poco ...
+1 para usar un signatario file.ext.end si es posible, donde el contenido de file.ext.end es una suma de comprobación para el archivo más grande. Esto no es tanto por seguridad como para asegurarse de que nada se distorsione en el camino. Si alguien puede insertar su propio archivo en la transmisión grande, también puede reemplazar la suma de comprobación.
A menos que el contenido de un archivo se pueda verificar para su finalización (tiene un formato verificable o incluye una suma de verificación de los contenidos), solo el remitente puede verificar que ha llegado un archivo completo.
He utilizado un método de bloqueo para enviar grandes archivos a través de FTP en el pasado.
El archivo se envía con una extensión alternativa y se renombra una vez que el remitente está contento de que esté todo allí.
Lo anterior obviamente se combina con un proceso que periódicamente ordena archivos viejos con la extensión temporal.
Una alternativa es crear un archivo de longitud cero con el mismo nombre pero con una extensión .lck adicional. Una vez que el archivo real está completamente cargado, el archivo lck se elimina. El proceso de recepción obviamente ignora los archivos que tienen el nombre de un archivo de bloqueo.
Sin un sistema como este, el receptor nunca puede estar seguro de que ha llegado el archivo completo.
La comprobación de archivos que no se han modificado en x minutos es propensa a todo tipo de problemas.
La forma en que verifico en Windows si un archivo ha sido cargado por completo por ftp es intentar cambiarle el nombre. Si el cambio de nombre falla, el archivo no está completo. No muy elegante, lo admito, pero funciona.
Probablemente tenga que ir con alguna señalización fuera de banda: haga que el productor de "file.ext" escriba un "archivo.ext.end" ficticio.
Si tiene el control del programa que está escribiendo los archivos en el directorio, puede hacer que el programa escriba los archivos en un directorio temporal y luego moverlos al directorio observado. El movimiento debería ser una operación atómica, por lo que el observador no debería ver el archivo hasta que esté completamente en el directorio.
Si no tiene el control de lo que está escribiendo en el directorio vigilado, puede establecer una hora en el observador donde el archivo se considera completo cuando ha permanecido del mismo tamaño para el tiempo determinado. Si el procesamiento inmediato no es una preocupación, establecer este temporizador a algo relativamente grande es una forma bastante segura de saber que el archivo está completo o que nunca lo estará.
Un bloqueo de escritura no ayuda si la carga del archivo falló parcialmente y el remitente no ha intentado volver a enviar (y volver a enganchar) el archivo.
El evento "Modificado" en FileSystemWatcher no debería activarse hasta que se cierre el archivo. Vea mi respuesta a una pregunta similar . Existe la posibilidad de que el mecanismo de descarga FTP cierre el archivo varias veces durante la descarga a medida que ingresan nuevos datos, pero creo que eso es un poco improbable.
El siguiente método intenta abrir un archivo con permisos de escritura. Bloqueará la ejecución hasta que un archivo esté completamente escrito en el disco:
/// <summary>
/// Waits until a file can be opened with write permission
/// </summary>
public static void WaitReady(string fileName)
{
while (true)
{
try
{
using (System.IO.Stream stream = System.IO.File.Open(fileName, FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite))
{
if (stream != null)
{
System.Diagnostics.Trace.WriteLine(string.Format("Output file {0} ready.", fileName));
break;
}
}
}
catch (FileNotFoundException ex)
{
System.Diagnostics.Trace.WriteLine(string.Format("Output file {0} not yet ready ({1})", fileName, ex.Message));
}
catch (IOException ex)
{
System.Diagnostics.Trace.WriteLine(string.Format("Output file {0} not yet ready ({1})", fileName, ex.Message));
}
catch (UnauthorizedAccessException ex)
{
System.Diagnostics.Trace.WriteLine(string.Format("Output file {0} not yet ready ({1})", fileName, ex.Message));
}
Thread.Sleep(500);
}
}
(de mi respuesta a una pregunta relacionada )