Question

Nous disposons de plusieurs applications .NET qui surveillent un répertoire pour détecter les nouveaux fichiers, à l'aide de FileSystemWatcher.Les fichiers sont copiés depuis un autre emplacement, téléchargés via FTP, etc.A leur arrivée, les dossiers sont traités d'une manière ou d'une autre.Cependant, un problème pour lequel je n'ai jamais trouvé de réponse satisfaisante est le suivant :pour les fichiers volumineux, comment savoir quand les fichiers surveillés sont encore en cours d'écriture ?Évidemment, il faudra attendre que les dossiers soient complets et fermés avant de commencer à les traiter.Les arguments d'événement dans les événements FileSystemWatcher ne semblent pas résoudre ce problème.

Était-ce utile?

La solution

Avez-vous essayé d'obtenir un verrou en écriture sur le fichier ?S'il est écrit, cela devrait échouer, et vous savez le laisser tranquille pendant un moment...

Autres conseils

Si vous contrôlez le programme qui écrit les fichiers dans le répertoire, vous pouvez demander au programme d'écrire les fichiers dans un répertoire temporaire, puis de les déplacer dans le répertoire surveillé.Le déplacement doit être une opération atomique, donc l'observateur ne doit pas voir le fichier tant qu'il n'est pas entièrement dans le répertoire.

Si vous ne contrôlez pas ce qui est écrit dans le répertoire surveillé, vous pouvez définir une heure dans l'observateur à laquelle le fichier est considéré comme terminé lorsqu'il est resté la même taille pendant la durée donnée.Si le traitement immédiat ne pose pas de problème, régler ce minuteur sur une valeur relativement importante est un moyen assez sûr de savoir si le fichier est complet ou s'il ne le sera jamais.

L'événement "Changed" sur FileSystemWatcher ne devrait pas se déclencher tant que le fichier n'est pas fermé.Voir mon réponse à une question similaire.Il est possible que le mécanisme de téléchargement FTP ferme le fichier plusieurs fois pendant le téléchargement à mesure que de nouvelles données arrivent, mais je pense que c'est un peu improbable.

À moins que le contenu d'un fichier puisse être vérifié et qu'il soit complet (il a un format vérifiable ou inclut une somme de contrôle du contenu), seul l'expéditeur peut vérifier qu'un fichier entier est arrivé.

J'ai déjà utilisé une méthode de verrouillage pour envoyer des fichiers volumineux via FTP.

Le fichier est envoyé avec une extension alternative et est renommé une fois que l'expéditeur est satisfait que tout est là.

Ce qui précède est évidemment combiné avec un processus qui nettoie périodiquement les anciens fichiers avec l'extension temporaire.

Une alternative consiste à créer un fichier de longueur nulle portant le même nom mais avec une extension .lck supplémentaire.Une fois le vrai fichier entièrement téléchargé, le fichier lck est supprimé.Le processus récepteur ignore évidemment les fichiers qui portent le nom d'un fichier de verrouillage.

Sans un système comme celui-ci, le destinataire ne peut jamais être sûr que l'intégralité du fichier est arrivée.

La recherche de fichiers qui n'ont pas été modifiés depuis x minutes est sujette à toutes sortes de problèmes.

La méthode suivante tente d'ouvrir un fichier avec des autorisations en écriture.Cela bloquera l'exécution jusqu'à ce qu'un fichier soit complètement écrit sur le disque :

/// <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);
    }
}

(d'après ma réponse à un question connexe)

Vous devrez probablement utiliser une signalisation hors bande :demandez au producteur de "file.ext" d'écrire un "file.ext.end" factice.

+1 pour utiliser un signaleur file.ext.end si possible, où le contenu de file.ext.end est une somme de contrôle pour le fichier plus volumineux.Ce n'est pas tant pour des raisons de sécurité que pour s'assurer que rien n'a été altéré en cours de route.Si quelqu'un peut insérer son propre fichier dans le flux volumineux, il peut également remplacer la somme de contrôle.

Un verrou en écriture n'aide pas si le téléchargement du fichier a échoué en cours de route et que l'expéditeur n'a pas encore essayé de renvoyer (et de reverrouiller) le fichier.

La façon dont je vérifie sous Windows si un fichier a été complètement téléchargé par FTP est d'essayer de le renommer.Si le changement de nom échoue, le fichier n'est pas complet.Pas très élégant, je l'avoue, mais ça marche.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top