Я работал над индикатором Dropbox для Wingpanel , и одна из функций, которые я пытался реализовать, - это список последних действий, то есть список самых последних измененных / созданные файлы.
Я знаю, что у нас есть inotify. Однако у него есть два ограничения:
- он не отслеживает изменения в подпапке;
- максимальное количество папок, которые вы можете просматривать одновременно.
Итак, мой подход следующий: Я просматриваю всю древовидную структуру сравнение дат изменения каждой папки. Если обнаруживается какое-то изменение, я подаю сигнал и останавливаюсь. Однако, чтобы избежать зависания 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);
}
}
}