Member 10536462 Ответов: 1

Как использовать filesystemwatcher и отправлять почту каждый раз, когда файл создается в папке?


Существует процесс, который мы запускаем, который создает файлы и записывает данные о конкретном событии. Файл создается в папке: C:\\EventListenerFolder\\ . Теперь всякий раз, когда создается новый файл и в него записываются данные, нам нужно отправить письмо.


public static void RunEventListenerPrgm()
{
// почтовое уведомление должно отправляться по мере того, как файл генерируется в C:\\EventListenerFolder\\
в то время как (правда)
{
Системы.ИО.Класса filesystemwatcher m_Watcher = новая система.ИО.Класса filesystemwatcher();
m_Watcher.Filter="*. txt";
m_Watcher.Путь = "C:\\EventListenerFolder\\";
m_Watcher.NotifyFilter = NotifyFilters.LastAccess | NotifyFilters.LastWrite | NotifyFilters.FileName | NotifyFilters.Каталог название;
m_Watcher.Изменено += новый FileSystemEventHandler(OnChanged);
m_Watcher.EnableRaisingEvents = true;
}
}

общественная статический недействительным событий onchanged(объект отправителя, FileSystemEventArgs е)
{
строки stringReceived;
строка[] сайт allfiles = система.ИО.Каталог.Заражен("C:\\EventListenerFolder\\");
foreach (строковый файл во всех файлах)
{
Приставка.WriteLine ("Найден Файл Соответствия EventListener. Имя файла: "+ file);
пробовать
{
stringReceived = система.ИО.Файл.ReadAllText(файл);
}
поймать (исключение бывший)
{
continue; / / чтобы избежать чтения файла, когда он находится в процессе записи . поэтому мы ждем, пока файл будет записан, а затем читаем его
}
SendMailFunction(stringReceived);
Файл.Удалить файлы);

}
}

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

Что я уже пробовал:

Попробовал сменить m_Watcher.Изменено += новый FileSystemEventHandler(OnChanged);
к m_Watcher.Created+= new FileSystemEventHandler(OnChanged);
все равно не работает.

Может быть, фильтр событий file watcher, который я использую, неверен?
Не могли бы вы помочь мне в том же самом?

1 Ответов

Рейтинг:
0

Richard Deeming

Так много проблем; с чего начать? :)

Ваш OnChanged обработчик событий игнорирует информацию о который файл изменен, и отправка уведомления для все файлы в папке. Вы должны использовать e.FullName чтобы обработать только тот файл, который изменился:

private static void OnChanged(object sender, FileSystemEventArgs e)
{
    string file = e.FullName;
    Console.WriteLine("EventListener Match File Found. FILE NAME : {0}", file);
    
    try
    {
        string stringReceived = File.ReadAllText(file);
        SendMailFunction(stringReceived);
        File.Delete(file);
    }
    catch (IOException)
    {
    }
}

Ваш RunEventListenerPrgm метод заключается в создании нескольких новых FileSystemWatcher экземпляры в плотном цикле. Каждый отдельный экземпляр, который вы создадите, вызовет OnChanged обработчик каждый раз, когда файл изменяется. Я поражен, что вам удалось получить только сотни сообщений для одного файла!

Метод никогда не завершится чисто, поэтому быстрым и грязным решением было бы переместить создание FileSystemWatcher экземпляр вне цикла:
public static void RunEventListenerPrgm()
{
    var m_Watcher = new System.IO.FileSystemWatcher
    {
        Filter = "*.txt",
        Path = @"C:\EventListenerFolder\",
        NotifyFilter = NotifyFilters.LastAccess | NotifyFilters.LastWrite | NotifyFilters.FileName | NotifyFilters.DirectoryName
    };
    
    m_Watcher.Created += OnChanged;
    m_Watcher.EnableRaisingEvents = true;
    
    while (true)
    {
    }
}

Однако это, вероятно, будет потреблять 100% одного из ваших процессорных ядер все время работы программы!

Немного лучшей альтернативой было бы использовать WaitForChanged метод:
public static void RunEventListenerPrgm()
{
    var m_Watcher = new System.IO.FileSystemWatcher
    {
        Filter = "*.txt",
        Path = @"C:\EventListenerFolder\",
        NotifyFilter = NotifyFilters.LastAccess | NotifyFilters.LastWrite | NotifyFilters.FileName | NotifyFilters.DirectoryName
    };
    
    while (true)
    {
        WaitForChangedResult result = m_Watcher.WaitForChanged(WatcherChangeTypes.Created | WatcherChangeTypes.Changed);
        if (!result.TimedOut)
        {
            OnChanged(result.Name);
        }
    }
}

private static void OnChanged(string file)
{
    Console.WriteLine("EventListener Match File Found. FILE NAME : {0}", file);
    
    try
    {
        string stringReceived = File.ReadAllText(file);
        SendMailFunction(stringReceived);
        File.Delete(file);
    }
    catch (IOException)
    {
    }
}

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

Наконец, существует известная проблема, когда FileSystemWatcher может генерировать несколько событий для одного и того же изменения. Существует множество обходных путей, которые можно найти - например:
Событие FileSystemWatcher Changed вызывается дважды-переполнение стека[^]
FileSystemWatcher генерирует повторяющиеся события – как обойти проблему-BizTalk 2006-адаптер Windows SharePoint Services[^]