Pregunta

Tenemos varias aplicaciones .NET que monitorean un directorio en busca de archivos nuevos, usando FileSystemWatcher.Los archivos se copian desde otra ubicación, se cargan mediante FTP, etc.Cuando llegan, los archivos se procesan de una forma u otra.Sin embargo, un problema para el que nunca he visto una respuesta satisfactoria es:para archivos grandes, ¿cómo se puede saber cuándo todavía se están escribiendo en los archivos que se están monitoreando?Obviamente, debemos esperar hasta que los archivos estén completos y cerrados antes de comenzar a procesarlos.Los argumentos de evento en los eventos de FileSystemWatcher no parecen solucionar este problema.

¿Fue útil?

Solución

¿Has intentado bloquear la escritura en el archivo?Si se está escribiendo, debería fallar, y debes dejarlo en paz por un momento...

Otros consejos

Si tiene el control del programa que escribe los archivos en el directorio, puede hacer que el programa escriba los archivos en un directorio temporal y luego los mueva al directorio supervisado.El movimiento debe 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 se escribe en el directorio supervisado, puede establecer un tiempo en el observador en el que el archivo se considere completo cuando haya permanecido del mismo tamaño durante el tiempo determinado.Si el procesamiento inmediato no es una preocupación, configurar este temporizador en algo relativamente grande es una forma bastante segura de saber si el archivo está completo o nunca lo estará.

El evento "Cambiado" en FileSystemWatcher no debería activarse hasta que se cierre el archivo.Mira 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.

A menos que se pueda verificar que el contenido de un archivo esté completo (tiene un formato verificable o incluye una suma de verificación del contenido), solo el remitente puede verificar que ha llegado un archivo completo.

En el pasado he utilizado un método de bloqueo para enviar archivos grandes a través de FTP.

El archivo se envía con una extensión alternativa y se le cambia el nombre una vez que el remitente está satisfecho de que esté todo allí.

Lo anterior obviamente se combina con un proceso que periódicamente ordena los archivos antiguos con 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 se carga por completo, 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 podrá estar seguro de que ha llegado el archivo completo.

La búsqueda de archivos que no se han modificado en x minutos es propensa a todo tipo de problemas.

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 un pregunta relacionada)

Probablemente tengas que optar por alguna señalización fuera de banda:haga que el productor de "file.ext" escriba un "file.ext.end" ficticio.

+1 por usar un señalizador file.ext.end si es posible, donde el contenido de file.ext.end es una suma de verificación para el archivo más grande.Esto no es tanto por seguridad sino para asegurarse de que nada se confunda en el camino.Si alguien puede insertar su propio archivo en la secuencia grande, también puede reemplazar la suma de verificación.

Un bloqueo de escritura no ayuda si la carga del archivo falló a mitad de camino y el remitente aún no ha intentado reenviar (y volver a bloquear) el archivo.

La forma en que compruebo en Windows si un archivo se ha cargado por completo mediante ftp es intentar cambiarle el nombre.Si falla el cambio de nombre, el archivo no está completo.No es muy elegante, lo admito, pero funciona.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top