Триггеры FileSystemWatcher для открытого потока

У меня есть файловая система, которая будет инициировать событие при изменении файла. Я хочу прочитать из этого файла после удаления блокировки. На данный момент я просто пытаюсь открыть файл после запуска события, когда копируется большой файл, блокировка файла остается на некоторое время после того, как события были отправлены, что предотвращает открытие файла для доступа на чтение.

Любые предложения?

Ответ 1

На самом деле это немного doozie, если пространство проблем существенно не изменилось с тех пор, как я последний раз имел дело с ним.

Самый простой способ - просто попытаться открыть файл, поймать полученный IOException, и если файл заблокирован, добавьте его в очередь, которую нужно проверить позже. Вы не можете просто попробовать обработать каждый файл, который приходит, потому что есть все случаи, когда несколько событий будут созданы для одного и того же файла, поэтому настройка цикла повтора на каждом отдельном полученном событии может быстро стать катастрофой. Вам нужно поставить их в очередь и проверить очередь с регулярным интервалом.

Вот шаблон базового класса, который поможет вам решить эту проблему:

public class FileMonitor : IDisposable
{
    private const int PollInterval = 5000;

    private FileSystemWatcher watcher;
    private HashSet<string> filesToProcess = new HashSet<string>();
    private Timer fileTimer;  // System.Threading.Timer

    public FileMonitor(string path)
    {
        if (path == null)
            throw new ArgumentNullException("path");

        watcher = new FileSystemWatcher();
        watcher.Path = path;
        watcher.NotifyFilter = NotifyFilters.FileName;
        watcher.Created += new FileSystemEventHandler(FileCreated);
        watcher.EnableRaisingEvents = true;

        fileTimer = new Timer(new TimerCallback(ProcessFilesTimer),
            null, PollInterval, Timeout.Infinite);
    }

    public void Dispose()
    {
        fileTimer.Dispose();
        watcher.Dispose();
    }

    private void FileCreated(object source, FileSystemEventArgs e)
    {
        lock (filesToProcess)
        {
            filesToProcess.Add(e.FullPath);
        }
    }

    private void ProcessFile(FileStream fs)
    {
        // Your code here...
    }

    private void ProcessFilesTimer(object state)
    {
        string[] currentFiles;
        lock (filesToProcess)
        {
            currentFiles = filesToProcess.ToArray();
        }
        foreach (string fileName in currentFiles)
        {
            TryProcessFile(fileName);
        }
        fileTimer.Change(PollInterval, Timeout.Infinite);
    }

    private void TryProcessFile(string fileName)
    {
        FileStream fs = null;
        try
        {
            FileInfo fi = new FileInfo(fileName);
            fs = fi.OpenRead();
        }
        catch (IOException)
        {
            // Possibly log this error
            return;
        }

        using (fs)
        {
            ProcessFile(fs);
        }

        lock (filesToProcess)
        {
            filesToProcess.Remove(fileName);
        }
    }
}

(Примечание. Я помню это из памяти здесь, так что это может быть не идеально - сообщите мне, если это глючит.)