Мониторинг изменений в папке с большим количеством подпапок? - PullRequest
2 голосов
/ 29 мая 2020

Я работал над индикатором Dropbox для Wingpanel , и одна из функций, которые я пытался реализовать, - это список последних действий, то есть список самых последних измененных / созданные файлы.

Я знаю, что у нас есть inotify. Однако у него есть два ограничения:

  1. он не отслеживает изменения в подпапке;
  2. максимальное количество папок, которые вы можете просматривать одновременно.

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

Итак, мой индикатор запускает этот поиск каждые 3 секунды. У меня это отлично сработало. Однако некоторые пользователи указали на ошибку Segmentation Fault именно во время выполнения этого поиска. В конкретном случае c структура папок содержит около 23 тыс. Файлов и папок.

Есть ли у кого-нибудь лучшее решение? Заранее всем спасибо!

Я публикую свой код ниже.

Следующий код выполняется каждые 3 секунды и создает новый поток, в котором я выполняю поиск изменений.

private async bool core () throws ThreadError {
        // Do not create a new Thread if there is another
        if (is_working == false) {
            is_working = true;
            SourceFunc callback = core.callback;

            ThreadFunc<bool> run = () => {
                File dir_root = File.new_for_path (path);
                try {
                    FileInfo info = dir_root.query_info ("*", 0);
                    string iso = info.get_modification_time().to_iso8601();
                    GLib.DateTime file_modification_date = new GLib.DateTime.from_iso8601 (iso, null);

                    // Check if the root dir has changed
                    if (last_check_date.compare (file_modification_date) == -1) {
                        is_working = false;
                        // emitting change signal
                        changed (info);
                    } else {
                        compare_modification_date (path, last_check_date);
                        is_working = false;
                    }

                    last_check_date = new DateTime.now_local ();
                    Idle.add ((owned)callback);

                    return true;

                } catch (Error e) {
                    print ("Error getting info: %s",e.message);
                    return false;
                }

            };

            new Thread<bool>("compare-dir", run);
            yield;
        }

        return true;
    }

Приведенный ниже код является рекурсивной функцией, которая выполняет работу по сравнению дат изменений.

private void compare_modification_date (string dir_path, GLib.DateTime d) {
        File dir = File.new_for_path (dir_path);
        //
            try {
                FileEnumerator files = dir.enumerate_children("*", FileQueryInfoFlags.NOFOLLOW_SYMLINKS, null);
                FileInfo info = files.next_file (null);
                while(info != null) {
                    if(info.get_file_type() == FileType.DIRECTORY && !info.get_name().has_prefix(".") ) {
                         string iso = info.get_modification_time().to_iso8601();
                         GLib.DateTime file_modification_date = new GLib.DateTime.from_iso8601 (iso, null);

                         if (d.compare(file_modification_date) == -1) {
                             print ("The dir %s has been modified.", info.get_name());
                             // emitting change signal
                             changed (info);
                             break;
                         } else {
                             compare_modification_date(dir_path+"/"+info.get_name(), d);
                             info =files.next_file (null);
                         }
                     } else {
                         info = files.next_file(null);
                     }
                }
            } catch (Error e) {
                print ("Error comparing dates:%s", e.message);
            }
     }

}

...