Контроль каталога для создания нового файла без FileSystemWatcher

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

Я начал с использования FileSystemWatcher . Мой босс не любит FileSystemWatcher и хочет, чтобы я использовал опрос с использованием Timer или любого другого механизма, кроме FileSystemWatcher .

Как вы можете контролировать каталогизацию, не используя FileSystemWatcher используя. NET Framework?

7
задан p.campbell 10 October 2013 в 20:09
поделиться

7 ответов

Используя ответ @Petoj, я включил полнофункциональную службу Windows, которая каждые пять минут опрашивает новые файлы. Это ограничено, поэтому только один поток опрашивает, учитывает время обработки и поддерживает паузу и своевременную остановку. Он также поддерживает простое присоединение отладчика к 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();
   }

 }
6
ответ дан 6 December 2019 в 05:42
поделиться

На самом деле компонент FileWatcher не является на 100% "стабильным", судя по моему многолетнему опыту. Поместите достаточно файлов в папку, и вы потеряете некоторые события. Это особенно верно, если вы отслеживаете общую папку, даже если вы увеличиваете размер буфера.

Итак, по всем практическим причинам используйте FileWatcher вместе с таймером, который сканирует папку на наличие изменений, для наиболее оптимального решения.

Примеров создания кода Timer должно быть предостаточно, если вы погуглите. Если вы отслеживаете последний DateTime при запуске таймера, проверьте дату изменения каждого файла и сравните ее с датой. Достаточно простая логика.

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

17
ответ дан 6 December 2019 в 05:42
поделиться

При запуске программы используйте Directory.GetFiles(path) для получения списка файлов.

Затем создайте таймер и в его прошедшем событии вызовите hasNewFiles:

    static List<string> hasNewFiles(string path, List<string> lastKnownFiles)
    {
        List<string> files = Directory.GetFiles(path).ToList();
        List<string> newFiles = new List<string>();

        foreach (string s in files)
        {
            if (!lastKnownFiles.Contains(s))
                newFiles.Add(s);
        }

        return new List<string>();
    }

В вызывающем коде у вас будут новые файлы, если:

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

изменить: если вы хотите более гибкое решение:

    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; 
    } 
4
ответ дан 6 December 2019 в 05:42
поделиться

Вы можете использовать Directory.GetFiles():

using System.IO;

var fileList = new List<string>();

foreach (var file in Directory.GetFiles(@"c:\", "*", SearchOption.AllDirectories))
{
    if (!fileList.Contains(file))
    {
        fileList.Add(file);
        //do something
    }
}

Обратите внимание, что это проверяет только новые файлы, а не измененные файлы, если вам это нужно, используйте FileInfo

4
ответ дан 6 December 2019 в 05:42
поделиться

Я бы спросил, почему бы не использовать FileSystemWatcher. Он регистрируется в ОС и немедленно получает уведомление, когда событие завершается в файловой системе.

Если вам действительно нужно провести опрос, просто создайте System.Timers.Timer, создайте метод для его вызова и проверьте наличие файла в этом методе.

1
ответ дан 6 December 2019 в 05:42
поделиться

Да, вы можете создать таймер и подключить обработчик к событию Elapsed, который создаст экземпляр класса DirectoryInfo для просматриваемого вами каталога и вызовет либо GetFiles(), либо EnumerateFiles(). GetFiles() возвращает массив FileInfo[], а EnumerateFiles() возвращает "потоковое" IEnumerable. EnumerateFiles() будет более эффективным, если вы ожидаете, что в этой папке будет много файлов, когда вы просматриваете; вы можете начать работать с IEnumerable до того, как метод получит все FileInfos, в то время как GetFiles заставит вас ждать.

Что касается того, почему это может быть на самом деле лучше, чем FileWatcher, это зависит от архитектуры за кулисами. Возьмем, к примеру, базовый рабочий процесс извлечения/преобразования/проверки/загрузки. Во-первых, такой рабочий процесс может потребовать создания дорогостоящих экземпляров объектов (соединений с БД, экземпляров механизма правил и т. д.). Эти единовременные накладные расходы значительно уменьшаются, если рабочий процесс структурирован для обработки всего, что ему доступно, за один раз. Во-вторых, FileWatcher потребует, чтобы все, что вызывается обработчиками событий, например этот рабочий процесс, было потокобезопасным, поскольку МНОГИЕ события могут выполняться одновременно, если файлы постоянно поступают. Если это невозможно, таймер можно очень легко настроить. чтобы ограничить систему одним запущенным рабочим процессом, заставив обработчики событий проверять потокобезопасный флаг «работа процесса» и просто завершать работу, если другой поток обработчика установил его и еще не завершил. Файлы в папке в это время будут выбраны при следующем срабатывании таймера, в отличие от FileWatcher, где, если вы завершаете обработчик, информация о существовании этого файла теряется.

1
ответ дан 6 December 2019 в 05:42
поделиться

1) Похоже, ваш начальник идиот
2) Вам придется использовать такие функции, как Directory.GetFiles, File.GetLastAccessTime и т. д., и хранить их в памяти, чтобы проверить, не изменились ли они.

0
ответ дан 6 December 2019 в 05:42
поделиться
Другие вопросы по тегам:

Похожие вопросы: