none
Проблемы с FileSystemWatcher RRS feed

  • Вопрос

  • Здравствуйте!

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

    Вот код создания экземпляров FileSystemWatcher:

                    //создаем вэтчер, следящий за каталогом комманд
                    if (_reserveSend != "")
                    {
                        MyWatcher fsw = new MyWatcher(_reserveSend);
    
                        fsw.NotifyFilter = System.IO.NotifyFilters.FileName | System.IO.NotifyFilters.LastWrite;
                        fsw.Filter = "gsb_need_send_*.gsb";
                        fsw.IncludeSubdirectories = true;
                        fsw.Created += new System.IO.FileSystemEventHandler(ReserveSend_ChangeOrCreate);
                        fsw.Changed += new FileSystemEventHandler(ReserveSend_ChangeOrCreate);
                        fsw.EnableRaisingEvents = true;
                        _reserveDirWatcher = fsw;
                    }
                    //создаем вэтчер, следящий за каталогом отправки (ставит статус "отправлен")
                    try
                    {
                        MyWatcher sfsw = new MyWatcher(_outDir);
                        sfsw.NotifyFilter = System.IO.NotifyFilters.FileName | System.IO.NotifyFilters.LastWrite;
                        sfsw.Deleted += new System.IO.FileSystemEventHandler(OutDir_FilesDeleted);
                        sfsw.Renamed += new RenamedEventHandler(OutDir_FilesDeleted);
                        sfsw.EnableRaisingEvents = true;
                        _outDirWatcher = sfsw;
                    }
                    catch (Exception ex)
                    {
                        OnError("Ошибка при запуске просмотрщика каталога отправки. Сообщение: " + ex.Message);
                    }
    
                    watchers.Clear();
                    settings.Clear();
                    settings.Add(new Settings("Part1", "0", "[!]Каталоги отчетов (для справки, не изменяются)"));
                    //создаем вэтчеры, следящие за каталогами отчетов.
                    foreach (DataRow myRow in ds.Tables["MyContent"].Rows)
                    {
                        try
                        {
                            string[] masks = myRow["REPORT_MASK"].ToString().Split(new string[] { ",", " ,", ", ", " , " }, StringSplitOptions.RemoveEmptyEntries);
                            if (masks.Length == 0) masks = new string[] { "*.*" };
                            foreach (string mask in masks)
                            {
                                //для отображения в консоли
                                settings.Add(new Settings(myRow["REPORT_FORM"].ToString(), myRow["REPORT_DIR"].ToString() + "\\" + mask, myRow["REPORT_FORM"].ToString()));
    
                                MyWatcher fsw = new MyWatcher(myRow["REPORT_DIR"].ToString());
                                fsw.NotifyFilter = System.IO.NotifyFilters.FileName | System.IO.NotifyFilters.LastWrite;
    
                                if (myRow["REPORT_ALL_DIR"].ToString() == "1") fsw.IncludeSubdirectories = true;
                                else fsw.IncludeSubdirectories = false;
    
                                string nm = "";
                                if (mask == string.Empty) nm = "*.*";
                                else nm = mask;
                                fsw.Filter = nm.Trim();
                                                            
                                fsw.ID_SETTINGS = (int)myRow["ID_SETTINGS"];
    
                                fsw.Created += new System.IO.FileSystemEventHandler(fsw_ChangeOrCreate);
                                fsw.Changed += new FileSystemEventHandler(fsw_ChangeOrCreate);
                                fsw.EnableRaisingEvents = true;
                                watchers.Add(fsw);
                            }
                        }
                        catch (Exception ex)
                        {
                            OnError("Ошибка при добавлении каталога " + myRow["REPORT_DIR"].ToString() + " отчета " + myRow["REPORT_FORM"].ToString() + ". Проверьте имя каталога. Сообщение: " + ex.Message);
                        }
                    }

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

    вот обработка срабатываний:

            void fsw_ChangeOrCreate(object sender, System.IO.FileSystemEventArgs e)
            {
                if (System.IO.Directory.Exists(e.FullPath)) return;
                try
                {
                    MyWatcher w = sender as MyWatcher;
    
                    string file = e.FullPath.Substring((sender as MyWatcher).Path.Length).TrimStart('\\');
                    if (file.Contains("\\")) file = "\\" + file.Remove(file.IndexOf("\\")) + "\\";
                    else file = "\\" + file;
    
                    AddAction da = new AddAction(w.ID_SETTINGS, w.Path, file);
    
                    lock (_locklist)
                    {
                        bool have = false;
                        foreach (AddAction dwaact in _add_actions)
                            if ((dwaact.Id_Setting == da.Id_Setting) && (dwaact.FileName.TrimEnd('\\') == da.FileName.TrimEnd('\\')))
                            {
                                have = true;
                                dwaact.Last_Write = DateTime.Now;
                                if (LastCharIs(dwaact.FileName, '\\') || LastCharIs(da.FileName, '\\')) dwaact.FileName = dwaact.FileName.TrimEnd('\\') + "\\";
                                OnError("DOUBLEFILE " + dwaact.FileName + " {} " + dwaact.Id_Setting.ToString());
                            }
                        if (!have)
                        {
                            _add_actions.Add(da);
                            if (!_add_timer.Enabled) _add_timer.Enabled = true;
                        }
                    }
                }
                catch (Exception ex)
                {
                    OnError("Watcher error: " + ex.Message);
                }                
            }

    На одном компьютере все работает, а на компе с ОС Microsoft Server 2003 срабатывают только 53 экземпляра  FileSystemWatcher (т.е. два служебных и 51 по загруженным из БД каталогам). Все остальные ошибок не выдают и уведомлений о изменении файлов тоже.

    В чем может быть проблема?

    14 марта 2014 г. 11:42

Ответы

  • Проблема решена.

    To resolve this issue, verify that the
    MaxCmds
    and
    MaxMpxCt
    registry values are set to 50 or more. To do this, follow these steps:
    1. Click Start, click   Run,  type   regedit, and then click OK.
    2. Locate and then click the following key in the registry:
      HKEY_LOCAL_MACHINE\ SYSTEM\ CurrentControlSet\ Services\ lanmanworkstation\ parameters
    3. In the right pane, double-click the   MaxCmds value.
    4. In the Value data box, verify that the value is 50 or more.

      Note  In a Microsoft Windows Terminal Services environment, you may have to set the 
      MaxCmds
      registry value to 500 or more.  For more information, click the following article number to view the article in the Microsoft Knowledge Base:
       
      Terminal Server client connections and logon limited by MaxWorkItem and MaxMpxCt values
    5. Locate and then click the following key in the registry:
      HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\lanmanserver\parameters
      Note  Make sure that you make this change to the
      lanmanserver\parameters
      registry key and not to the
      lanmanworkstation\parameters
      registry key mentioned in step 2.
    6. In the right-pane, double-click the   MaxMpxCt value.

      Note  On SMB servers that are running a version of Windows earlier than Windows 2000, the
      MaxMpxCt
      registry entry is named  
      MaxMpxCount
      , but has the same function.
    7. In the Value data box, verify that the value is 50 or more.

      Note  The
      MaxMpxCt
      value determines the maximum number of simultaneous, active requests that the server permits from an individual client.
    8. Quit Registry Editor.
    9. Restart the server.
    • Помечено в качестве ответа D_W_A_ 18 марта 2014 г. 9:23
    18 марта 2014 г. 9:22

Все ответы

  • В описании FileSystemWatcher'а сказано, что события могут теряться, когда переполнен внутренний буфер. Можно попробовать увеличить InternalBufferSize.

    15 марта 2014 г. 6:33
  • Нет. Там событий не так много. Те 53 которые работают - они ничего не пропускают. На 54 экземпляр и последующих события вообще не приходят.
    17 марта 2014 г. 4:36
  • Точного ответа я не знаю, поэтому выскажу разные предположения, которые приходят в голову.

    Из описания FileSystemWatcher:

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

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

    • Код обработки событий должен быть как можно более коротким.

    Мои советы:

    1. Всё-таки попробуйте увеличить InternalBufferSize.

    2. Как я могу видеть по коду, два FSW создаются отдельно, остальные несколько десятков в цикле и заносятся в List. Так? При этом вижу очистку списка: watchers.Clear(); Как часто это происходит? Дело в том, что FileSystemWatcher реализует IDisposable, поэтому хорошо бы явно вызывать метод Dispose, чтобы освободить ресурсы.

    3. Маловероятное предположение, но всё же: при работе с таймерами иногда случается такая ошибка: таймер создаётся, на его событие Tick навешивается слушатель, а далее по коду на этот таймер нет ссылок - и сборщик мусора удаляет его, отчего событие перестаёт вызываться. Это трудноуловимая проблема, т. к. срабатывает не всегда. Так вот, не может ли происходить нечто подобное в данном случае? Все ли FSW (которые не работают) хранятся в List? А сам список доживает до конца работы FSW? Можно попробовать поставить в самом конце программы GC.KeepAlive(watchers) на этот список (и на те FSW, которые не хранятся в списке).

    4. Имеются ли разрешения (permissions) к тем папкам, за которыми следят FSW?

    5. Вы пишете, что событий не много. Но обрабатываются они все одним методом. Долго ли выполняется этот метод? В частности, Directory.Exists, как и любые дисковые операции, не шибко быстрый. Не происходит ли конкурентный доступ к методу? Вот и теряется часть событий. Честно говоря, не могу сходу сказать, нужно ли в данном случае переместить блокировку lock выше по коду.

    17 марта 2014 г. 8:43
  • Проблема решена.

    To resolve this issue, verify that the
    MaxCmds
    and
    MaxMpxCt
    registry values are set to 50 or more. To do this, follow these steps:
    1. Click Start, click   Run,  type   regedit, and then click OK.
    2. Locate and then click the following key in the registry:
      HKEY_LOCAL_MACHINE\ SYSTEM\ CurrentControlSet\ Services\ lanmanworkstation\ parameters
    3. In the right pane, double-click the   MaxCmds value.
    4. In the Value data box, verify that the value is 50 or more.

      Note  In a Microsoft Windows Terminal Services environment, you may have to set the 
      MaxCmds
      registry value to 500 or more.  For more information, click the following article number to view the article in the Microsoft Knowledge Base:
       
      Terminal Server client connections and logon limited by MaxWorkItem and MaxMpxCt values
    5. Locate and then click the following key in the registry:
      HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\lanmanserver\parameters
      Note  Make sure that you make this change to the
      lanmanserver\parameters
      registry key and not to the
      lanmanworkstation\parameters
      registry key mentioned in step 2.
    6. In the right-pane, double-click the   MaxMpxCt value.

      Note  On SMB servers that are running a version of Windows earlier than Windows 2000, the
      MaxMpxCt
      registry entry is named  
      MaxMpxCount
      , but has the same function.
    7. In the Value data box, verify that the value is 50 or more.

      Note  The
      MaxMpxCt
      value determines the maximum number of simultaneous, active requests that the server permits from an individual client.
    8. Quit Registry Editor.
    9. Restart the server.
    • Помечено в качестве ответа D_W_A_ 18 марта 2014 г. 9:23
    18 марта 2014 г. 9:22