Как я могу последовательно обрабатывать элементы из очереди в C # .NET

Я пишу программное обеспечение для Windows в Visual Studio 2012, написанное на C #.

Используя класс FileSystemWatcher, я отслеживаю изменения в каталоге: если в каталог добавляются один или несколько новых файлов, класс FileSystemEventHandler запускает событие.

Это событие добавляет имена файлов в массив.

Затем я хочу обработать массив, а именно: обработать каждый файл (доступ через имя файла) в массиве и что-то сделать с файлом.

Теперь: мне нужно убедиться, что обработка файлов происходит последовательно. Посмотрите на файл 1, обработайте его и только после этого посмотрите на файл 2, обработайте его и так далее.

Обработка файла занимает около 5 секунд на файл. Между тем, в каталог могут быть добавлены новые файлы, и, таким образом, класс FileSystemEventHandler сработает из-за этих изменений. Но я не хочу, чтобы это происходило - всегда должен обрабатываться только один файл за раз - независимо от того, сколько раз запускается событие для изменений!

Кто-нибудь может предоставить мне шаблон (или фрагмент кода) для этого, пожалуйста ?!


person Sebastian    schedule 22.10.2013    source источник
comment
Microsoft предоставляет образец кода, который делает в значительной степени именно то, что вам нужно: msdn.microsoft .com / ru-ru / library / dd997371.aspx   -  person Baldrick    schedule 22.10.2013
comment
Спасибо @Baldrick за указание на это!   -  person Sebastian    schedule 22.10.2013


Ответы (5)


Я думаю, что следующий класс был бы оптимальным,

BlockingCollection<T> Класс

Предоставляет возможности блокировки и ограничения для поточно-ориентированных коллекций, реализующих IProducerConsumerCollection.

Он действует как параллельная очередь, и вы можете обрабатывать элементы асинхронно с помощью задач.

Альтернативой будет ConcurrentQueue<T>, но BlockingCollection дает вам две важные функции

Это потокобезопасный

Когда вы вызываете Take(), он будет блокироваться (т. Е. Ждать, пока что-то не окажется в очереди) для вас, поэтому вам не нужно писать какой-либо код с ManualResetEvents и т.п., что является хорошим упрощением.

person Rajesh Subramanian    schedule 22.10.2013
comment
Спасибо, это именно то, что я искал! - person Sebastian; 22.10.2013

Вы также можете использовать структуру RX.

Что-то вроде этого:

public static Tuple<FileSystemWatcher, Task> Watch(this string path, Action<string> processNewFile)
{
    var watcher = new FileSystemWatcher(path) {EnableRaisingEvents = true};
    return
        Tuple.Create(
            watcher,
            Observable
                .FromEventPattern<FileSystemEventHandler, FileSystemEventArgs>(
                    handler => watcher.Created += handler,
                    handler => watcher.Created -= handler)
                .Select(pattern => pattern.EventArgs.FullPath)
                .ForEachAsync(processNewFile));
}

Этот подход является асинхронным -дружелюбным, кратким и устраняет необходимость писать много шаблонного кода.

person galenus    schedule 22.10.2013
comment
Спасибо @galenus, это тоже хорошо! Но я пойду путем MS и буду придерживаться BlockingCollection ‹T›! - person Sebastian; 22.10.2013
comment
RX - это способ MS. Найдите интерфейсы IObservable и IObserver в mscorlib. Причина, по которой они не включают RX в ядро ​​.Net, заключается в том, что им нравится сохранять свободу внецикловых выпусков. Но выбор, конечно же, за вами :) - person galenus; 22.10.2013

Вам нужен шаблон, в котором FileSystemEventHandler просто добавляет имена файлов в общую очередь.

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

Таким образом, нет необходимости «останавливать» обработчик событий от добавления элементов во время обработки файла. Он может продолжать добавлять больше, и это не повлияет на рабочий поток.

Я бы предложил что-то вроде класса ConcurrentQueue для управления списком обрабатываемых файлов.

В следующем примере кода от Microsoft показано, как использовать BlockingCollection (которая является оболочкой ConcurrentQueue) для достижения этой цели:

http://msdn.microsoft.com/en-us/library/dd997371.aspx

person Baldrick    schedule 22.10.2013
comment
Без проблем. Отредактировал ответ, чтобы включить ссылку, так как она была вам полезна. - person Baldrick; 22.10.2013

Вам необходимо использовать Queue. очередь должна обрабатываться в отдельном потоке. поэтому вы можете обрабатывать список массивов файлов, не вмешиваясь в событие папки просмотра

person Izikon    schedule 22.10.2013

Вы можете установить логическую переменную, для которой установлено значение true, если обрабатывается другой файл, и значение false после его завершения. Между тем, если FileSystemEventHandler запускает новое событие, он проверяет переменную, которая, если установлено значение true, будет ждать. В противном случае установите для переменной значение true и продолжайте.

person Wasiq Ali    schedule 22.10.2013