Surveiller fichiers créés avec filesystemwatcher amélioré

Description

Ce programme permet de traiter des fichiers créés dans un dossier donné.
Cela marche actuellement pour des copies de fichier, pas pour des fichiers dézippés par exemple, ni avec SuperCopier.
Le traitement du fichier est fait dans un thread séparé.
On peut mettre en pause le traitement pendant que le FileSystemWatcher continue de surveiller le dossier.
Les commentaires sont en anglais.
Attention, pour tester il faut bien copier les fichier, et non les déplacer. Le code ci-dessous supprime le fichier copié.

Source / Exemple :


using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Threading;

namespace FileWatcher
{
    public partial class Form1 : Form
    {
        FileSystemWatcher myWatcher;
        string scanFolder = @"c:\"; // Folder to scan
        string fileMask = "*.*";

        Dictionary<string, int> filesLastWrite;
        Queue<string> queue;
        static readonly Object objLockQueue = new Object();

        System.Threading.Timer timer;
        bool cancelPending;
        delegate void reportProgressDelegate(int percentProgress, string message);
        delegate void stopScanDelegate();

        public Form1()
        {
            InitializeComponent();
            Init();
        }

        private void Init()
        {
            // Timers
            AutoResetEvent autoEvent = new AutoResetEvent(false);
            // Integrator
            System.Threading.TimerCallback timerDelegate = new System.Threading.TimerCallback(this.timer_Tick);
            timer = new System.Threading.Timer(timerDelegate, autoEvent, Timeout.Infinite, Timeout.Infinite);

            filesLastWrite = new Dictionary<string, int>();
            queue = new Queue<string>();

            myWatcher = new FileSystemWatcher(scanFolder, fileMask);
            myWatcher.NotifyFilter = NotifyFilters.LastWrite; 
            myWatcher.Changed += new FileSystemEventHandler(myWatcher_Changed);
            myWatcher.SynchronizingObject = this;
            // Activer
            myWatcher.EnableRaisingEvents = true;

            // Integrator
            this.btnStart.Enabled = true;
            this.btnStop.Enabled = false;
            this.lblState.Text = "Stopped";
        }

        void myWatcher_Changed(object sender, FileSystemEventArgs e)
        {
            lock (objLockQueue)
            {
                if (filesLastWrite.ContainsKey(e.FullPath))
                {
                    FileInfo fileInfo = new FileInfo(e.FullPath);
                    int nbTotalAccess;
                    int nbWriteAccess = filesLastWrite[e.FullPath] + 1;

                    // 3x for file copy, 2x if file size = 0
                    if (fileInfo.Length > 0)
                        nbTotalAccess = 3;
                    else
                        nbTotalAccess = 2;

                    if (nbWriteAccess < nbTotalAccess)
                        filesLastWrite[e.FullPath] = nbWriteAccess + 1;
                    else
                    {
                        filesLastWrite[e.FullPath] = 0;
                        queue.Enqueue(e.FullPath);
                    }
                }
                else
                    filesLastWrite.Add(e.FullPath, 1);
            }
        }

        void timer_Tick(Object stateInfo)
        {
            if (queue.Count > 0)
            {
                string fileNameFull;
                int nbFichiersTraites = 0;
                while (queue.Count > 0)
                {
                    // Cancel ?
                    if (cancelPending)
                    {
                        this.Invoke(new stopScanDelegate(this.StopScan));
                        return;
                    }
                    // Progress
                    int percentProgress;
                    nbFichiersTraites++;
                    lock (objLockQueue)
                    {
                        percentProgress = (int)100 * nbFichiersTraites / (queue.Count + nbFichiersTraites - 1);
                        fileNameFull = queue.Dequeue();
                    }
                    string message = percentProgress + "%" + " Processing file " + Path.GetFileName(fileNameFull);
                    this.Invoke(new reportProgressDelegate(this.reportProgress), new Object[] { percentProgress, message });

                    // Launch file operation
                    OperateFile(fileNameFull);
                }
            }
            // cancel ?
            if (cancelPending)
            {
                this.Invoke(new stopScanDelegate(this.StopScan));
                // The timer is not reactivated
            }
            else
            {
                // Progression
                this.Invoke(new reportProgressDelegate(this.reportProgress), new Object[] { 0, "Scanning..." });
                // Activate timer (1 time, in 1 second)
                timer.Change(1000, Timeout.Infinite);
            }
        }

        private void OperateFile(string fileNameFull)
        {
            Console.WriteLine("Operating file " + fileNameFull);
            // ...
            // Work with this file
            // ...
            File.Delete(fileNameFull); // by example
        }

        public void reportProgress(int percentProgress, string message)
        {
            this.progressBar.Value = percentProgress;
            this.lblState.Text = message;
        }

        private void btnStop_Click(object sender, EventArgs e)
        {
            btnStop.Enabled = false;
            // Cancel operation for the next file
            cancelPending = true;
        }

        private void StopScan()
        {
            // Timer is already off
            cancelPending = false;
            reportProgress(0, "Stopped.");

            this.btnStop.Enabled = false;
            this.btnStart.Enabled = true;
            this.btnStart.Focus();
        }

        private void btnStart_Click(object sender, EventArgs e)
        {
            BeginScan();
        }

        private void BeginScan()
        {
            this.btnStop.Enabled = true;
            this.btnStop.Focus();
            this.btnStart.Enabled = false;

            timer.Change(0, Timeout.Infinite); // Activate timer now (1 time)
        }
    }
}

Conclusion :


Pourquoi ne pas utiliser l'évènement OnCreate ? Parce que pour les gros fichiers, on est confrontée à l'erreur suivante :
Le processus ne peut pas accéder au fichier 'xxx', car il est en cours d'utilisation par un autre processus.

Pourquoi de pas utiliser OnChange + NotifyFilter.LastAccess ?
Parce qu'il loupe parfois des fichiers de petite taille.

J'attends vos commentaires !

Codes Sources

A voir également

Vous n'êtes pas encore membre ?

inscrivez-vous, c'est gratuit et ça prend moins d'une minute !

Les membres obtiennent plus de réponses que les utilisateurs anonymes.

Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.

Le fait d'être membre vous permet d'avoir des options supplémentaires.