7
votes

Surveillance d'un répertoire pour une nouvelle création de fichier sans fichiersSystemwatcher

Je dois créer un service Windows qui surveille un dossier spécifié pour les nouveaux fichiers et le traite et le déplace vers un autre emplacement.

J'ai commencé avec l'utilisation de fichiersystemwatcher . Mon patron n'aime pas FileSystemwatcher et veut que j'utilise l'interrogation en utilisant un minuteur ou tout autre mécanisme autre que FileSystemwatcher .

Comment pouvez-vous surveiller le répertoire sans utiliser fichiersystemwatcher à l'aide de la framework .NET?


4 commentaires

Peut-être qu'un test de quand vous devriez vous battre contre votre avis de votre patron ... Remplacer par un mécanisme de vote sonne comme une conversation folle


Pourquoi votre patron ne veut-il pas utiliser Watcher FileSystem? La raison pourrait indiquer la meilleure solution. S'il n'y a pas de raison, @giorgi a probablement la bonne réponse.


Allemagne FileSyst Systemwatcher ne fonctionne pas sur les lecteurs de réseau, et je ressens personnellement des cas où elle ne déclenche pas.


Tous les événements dans le monde Windows ne peuvent pas être approuvés et sont fiables. Peut-être qu'il travaille sur un système critique et a-t-il trouvé des problèmes avec des événements FileSystemwatcher dans leur environnement? On dirait bien cela pour moi. Il est facile de bash quand vous n'avez pas d'indice.


8 Réponses :


1
votes

Je voudrais interroger pourquoi ne pas utiliser le fichier de fichiers Systemwatcher. Il enregistre avec le système d'exploitation et est immédiatement notifié lorsque l'événement se termine dans le système de fichiers.

Si vous avez vraiment un sondage, créez simplement un système.timers.Timer, créez une méthode pour pouvoir appeler et rechercher le fichier dans cette méthode.


0 commentaires

4
votes

Vous pouvez utiliser répertoire.getfiles () : xxx

Remarque Ceci ne vérifie que les nouveaux fichiers non modifiés, si vous en avez besoin d'utiliser FileInfo


4 commentaires

Merci Petoj, votre réponse m'a donné le headstart dont j'avais besoin.


J'aimerais faire +1 mais je n'ai pas assez de réputation ou je suis juste très nouveau sur ce site car je ne sais pas comment le faire.


@ MD1337 Si le patron dit simplement que je n'aime pas ça, alors ne l'utilisez pas, puis je suis mes yeux, il est bizarre? (au moins il pourrait lui dire pourquoi il ne devrait pas l'utiliser?)


@Petoj, peut-être qu'il lui a dit que FilesSystemwatcher n'est pas fiable, ce qui est vrai. Vous devez l'utiliser conjointement avec le sondage ou utiliser l'interrogation seul. J'utilise personnellement FileSystemwatcher et interrogation. De cette façon, j'ai le meilleur des deux mondes: détection de fichier instantanée et détection garantie. Donc, le patron avait vraiment eu un point et il cherche à avoir une expérience de fichiersSystèmes.



0
votes

1) sonne comme votre patron est un idiot
2) Vous devrez utiliser des fonctions telles que le répertoire.getfiles, le fichier.getlastaccesstime, etc. et le garder en mémoire pour vérifier si cela a changé.


0 commentaires

0
votes

Il est un peu étrange que vous ne puissiez pas utiliser FileSystemwatcher code> ou vraisemblablement aucune des API Win32 qui font la même chose, mais cela n'est pas pertinent à ce stade. La méthode de vote pourrait ressembler à ceci.

public class WorseFileSystemWatcher : IDisposable
{
  private ManaulResetEvent m_Stop = new ManaulResetEvent(false);

  public event EventHandler Change;

  public WorseFileSystemWatcher(TimeSpan pollingInterval)
  {
    var thread = new Thread(
      () =>
      {
        while (!m_Stop.WaitOne(pollingInterval))
        {
          // Add your code to check for changes here.
          if (/* change detected */)
          {
            if (Change != null)
            {
              Change(this, new EventArgs())
            }
          }
        }
      });
    thread.Start();
  }

  public void Dispose()
  {
    m_Stop.Set();
  }
}


0 commentaires

17
votes

En réalité, le composant FileWatcher n'est pas 100% "stable" de mon expérience au fil des ans. Poussez suffisamment de fichiers dans un dossier et vous perdrez des événements. Ceci est particulièrement vrai si vous surveillez une part de fichier, même si vous augmentez la taille de la mémoire tampon.

Donc, pour toutes les raisons pratiques, utilisez FileWatcher avec une minuterie qui scanne un dossier pour les modifications, pour la solution la plus optimale.

Des exemples de code de minuterie de création doivent être en abondance si vous le gérez. Si vous gardez une trace de la dernière dateTime lorsque la minuterie a couru, vérifiez la date modifiée de chaque fichier et comparez-la à la date. Logique assez simple.

L'intervalle de minuterie dépend de la manière dont les changements sont urgents pour votre système. Mais vérifier chaque minute devrait être bien pour de nombreux scénarios.


7 commentaires

+1 Ceci est la bonne solution: FileWatcher Plus Sondage comme une sauvegarde pour gérer ce que FileWatcher manque. -1 Tous ceux qui pensent que le fichierwatcher est fiable.


La plupart des problèmes de fiabilité FileSystemWatcher provenaient d'un malentendu de la manière dont cela fonctionne. L'événement modifié n'est pas soulevé lorsqu'une écriture sur le disque est la file d'attente, mais ne sera augmentée qu'après que l'écriture a été commise. L'écriture derrière le cache de disque peut avoir une incidence sur la rapidité des événements en les retardant indéfiniment. La solution signalée consiste à rincer le cache via flushfilebuffer . Je suppose qu'il existe d'autres problèmes avec des actions réseau ayant un impact négatif sur la fiabilité.


@Brian: très bonne explication, et je n'ai pas pensé au cache d'écriture. Pour les actions réseau, la taille du trafic SMB est trop petite pour transférer tous les événements. Certains risquent donc de se perdre.


Je suis d'accord avec l'utilisation de fichiersSystemwatcher + interrogation. Notez que beaucoup d'événements "manqués" lors de la gestion de plusieurs fichiers sont parce que l'observateur crée un nouveau thread pour chaque événement, et si ce fil prend trop de temps pour exécuter le tampon remplira et que de nouveaux événements seront jetés. La solution consiste à apparaître un nouveau fil à l'intérieur du rappel et à travailler là-bas, et pas à rien d'autre dans le rappel.


Belle entrée @ MD1337. Ainsi, augmentant ainsi les tampons et les fils de frai et éventuellement modifier également le nombre maximal de threads pour votre application pourraient être la voie à suivre pour rendre les événements aussi «robustes» que possible.


Je pense que Brian Gideon l'a frappé sur le nez. L'événement modifié devrait être suffisant pour les fichiers entrants lentement. Cet événement continue de tirer continuellement jusqu'à ce que l'écriture de fichier soit terminée. Jusqu'à présent, je n'ai pas vu de "Miss" en utilisant cette méthode.


Je sais que c'est un peu vieux, mais je suis un peu confus pour combiner une méthode d'interrogation / une minuterie avec FileWatcher. Qu'est-ce qui empêche à la fois le polleur et le fichierwatcher de tenter de traiter le même fichier?



4
votes

au démarrage du programme, utilisez Directory.getFiles (Chemin) pour obtenir la liste des fichiers.

Créez ensuite une minuterie et dans son appel d'événement écoulé, appelez-vous: p>

    static IEnumerable<string> hasNewFiles(string path, List<string> lastKnownFiles)
    {
        return from f in Directory.GetFiles(path) 
               where !lastKnownFiles.Contains(f) 
               select f;
    }

    List<string> newFiles = hasNewFiles(path, lastKnownFiles); 
    if (newFiles.Count() > 0) 
    { 
        processFiles(newFiles); 
        lastKnownFiles = newFiles; 
    } 


1 commentaires

Merci Snorfus. Votre réponse a été très utile.



1
votes

Oui, vous pouvez créer une minuterie et brancher un gestionnaire dans l'événement écoulé qui instancera une classe DIRITERIFO pour le répertoire que vous observez et appelle des getfiles () ou énuméraires (). GetFiles () renvoie un tableau FILEInfo [], tandis que EnumateFiles () renvoie un "streaming" ienumerable. EnuméèrentFiles () sera plus efficace si vous vous attendez à ce que beaucoup de fichiers soient dans ce dossier lorsque vous regardez; Vous pouvez commencer à travailler avec l'iEnumerable avant que la méthode ait récupéré tous les fichiersInfos, tandis que GetFiles vous fera attendre.

Pourquoi cela peut en réalité être meilleur que FileWatcher, cela dépend de l'architecture des coulisses. Prenons, par exemple, un extrait de base / transformer / valider / charger le flux de travail. Premièrement, un tel flux de travail peut avoir à créer des instances coûteuses d'objets (connexions DB, des instances d'un moteur de règles, etc.). Cette surcharge ponctuelle est considérablement atténuée si le flux de travail est structuré de gérer tout ce qui est disponible en une seule fois. Deuxièmement, FileWatcher nécessiterait tout appelé par les gestionnaires d'événements, tels que ce flux de travail, pour être thread-coffre-fort, car de nombreux événements peuvent être en cours d'exécution à la fois si les fichiers s'écoulent constamment. Si cela n'est pas réalisable, une minuterie peut être très facilement configurée. Pour limiter le système à un flux de travail en cours d'exécution, en passant par les manutentionnaires d'événements, examinez un drapeau «processus de fonctionnement du processus» de thread-coffre-fort et vous terminez simplement si un autre fil de gestionnaire a défini et non encore terminé. Les fichiers du dossier à cette époque seront choisis la prochaine fois que la minuterie incendie, contrairement à FileWatcher, où si vous terminez le gestionnaire, les informations sur l'existence de ce fichier sont perdues.


0 commentaires

6
votes

Utilisation de la réponse de @ Petoj J'ai inclus un service Windows complet qui interroge toutes les cinq minutes pour les nouveaux fichiers. Son contraind n'est donc que seul un scrutin de thread, représente le temps de traitement et les supports de pause et une interruption en temps voulu. Il prend également en charge la fixation facile d'un debbugger sur System.Start

 public partial class Service : ServiceBase{


    List<string> fileList = new List<string>();

    System.Timers.Timer timer;


    public Service()
    {
        timer = new System.Timers.Timer();
        //When autoreset is True there are reentrancy problems.
        timer.AutoReset = false;

        timer.Elapsed += new System.Timers.ElapsedEventHandler(DoStuff);
    }


    private void DoStuff(object sender, System.Timers.ElapsedEventArgs e)
    {
       LastChecked = DateTime.Now;

       string[] files = System.IO.Directory.GetFiles("c:\\", "*", System.IO.SearchOption.AllDirectories);

       foreach (string file in files)
       {
           if (!fileList.Contains(file))
           {
               fileList.Add(file);

               do_some_processing();
           }
       }


       TimeSpan ts = DateTime.Now.Subtract(LastChecked);
       TimeSpan MaxWaitTime = TimeSpan.FromMinutes(5);

       if (MaxWaitTime.Subtract(ts).CompareTo(TimeSpan.Zero) > -1)
           timer.Interval = MaxWaitTime.Subtract(ts).TotalMilliseconds;
       else
           timer.Interval = 1;

       timer.Start();
    }

    protected override void OnPause()
    {
        base.OnPause();
        this.timer.Stop();
    }

    protected override void OnContinue()
    {
        base.OnContinue();
        this.timer.Interval = 1;
        this.timer.Start();
    }

    protected override void OnStop()
    {
        base.OnStop();
        this.timer.Stop();
    }

    protected override void OnStart(string[] args)
    {
       foreach (string arg in args)
       {
           if (arg == "DEBUG_SERVICE")
                   DebugMode();

       }

        #if DEBUG
            DebugMode();
        #endif

        timer.Interval = 1;
        timer.Start();
   }

   private static void DebugMode()
   {
       Debugger.Break();
   }

 }


3 commentaires

Merci pour votre réponse. Je suis confus sur la façon dont la minuterie fonctionne. Dans "do_some_processing", j'ai une zippation et un cryptage de fichiers volumineux et également des opérations de base de données. Les deux sont assez intensives. Que se passe-t-il lorsque l'opération dit prend plus que (juste imaginer) 5 minutes (l'intervalle de vote). Supposons que le traitement ait pris 6 minutes, donc si je comprends votre code correctement, il permettra 6 min pour traiter puis commencer la minuterie? Avant de voir votre code, j'utilisais une minuterie avec l'intervalle de 30 secondes et a ainsi été confondu ce qui se passe lorsque la minuterie s'écoule au milieu de la transformation.


Merci Conrad, enfin, j'ai pu créer mon service et votre réponse était assez utile.


Le code manque au classet déclaration de variable .