отслеживание переименования/удаления файлов с помощью FSEvents на Lion

Я пытаюсь использовать FSEvents, чтобы определить, когда файлы были добавлены/удалены из определенной папки. На данный момент я реализовал простую оболочку вокруг FSEvents, и она отлично работает: я получаю все события.

НО проблема, с которой я столкнулся сейчас, заключается в том, что когда я переименовываю файл в Finder, я ловлю 2 разных события: первое типа «переименовано» со старым именем файла, а другое — «переименовано» и новое имя файла. Идентификаторы событий различаются для обоих вызовов.

Итак, как я должен знать, какое «переименованное» событие содержит старое имя, а какое — старое?? Я пытался искать в документации, но, к сожалению, kFSEventStreamEventFlagItemRenamed не задокументирован ... кажется, это новое в Lion.

PS: единственный способ, который я мог придумать, был: в переименованном событии я проверяю свой пользовательский интерфейс, чтобы увидеть, есть ли у меня элемент, соответствующий пути события. Если это так, я отмечаю его для переименования. Если нет, я проверяю, был ли элемент помечен для переименования, и если да, то я переименовываю его в новый путь события. Но мне очень не нравится эта идея...

Редактировать: Хорошо, я что-то реализовал в строке моего «PS»: я заметил, что при переименовании чего-то идентификаторы двух событий являются последовательными, так что с идентификатором события, содержащего новое имя, я могу получить событие содержащие старое имя. Я просто использую небольшой словарь в своем интерфейсе для хранения идентификаторов и связанных путей в случае «переименованного» события.

Во всяком случае, теперь я могу перехватывать события переименования и даже события перемещения: когда вы перемещаете файл, это событие «переименование», которое перехватывается FSEventStream...

Но у меня все еще есть одна последняя проблема: удаление. Когда я что-то удаляю, оно перемещается в корзину: я получаю событие «переименование». Но проблема в том, что я не получаю второе событие переименования. Только "модифицированное" событие в файле .DS_Store. Я думаю, что этот файл используется Finder, чтобы узнать, какие файлы находятся в корзине и т. Д. Поэтому я мог бы проверить модификацию этого файла и получить последнее «переименованное» событие, чтобы определить, что файл был отправлен в корзину. Но я использую TotalFinder, который использует Asepsis, который изменяет способ хранения файлов .DS_Store в Finder: я больше не получаю «модифицированный» в этом случае. Подводя итог: я не могу определить, когда файл отправляется в корзину...

Любая идея, как я могу это сделать? Может быть, использовать что-то еще, кроме FSEvents, чтобы поймать только это событие?


person Citron    schedule 04.09.2011    source источник


Ответы (2)


Ну, я не нашел идеального ответа на свой вопрос, но я нашел решение, которым я в конечном итоге был очень доволен, поэтому я подумал, что могу поделиться ^^

Как я уже сказал, при перемещении материала в корзину, если вы просматриваете только 1 папку, вы не поймаете событие, сгенерированное при помещении изображения в корзину. Итак, я решил сделать следующее: у меня есть класс, который создает поток в корневой папке ("/"), чтобы он перехватывал все события -> это решает проблему отправки файлов в корзину, и все такие вещи. Затем этот класс позволяет регистрировать делегатов на определенных путях. Таким образом, вместо создания множества потоков я создаю один большой поток, затем фильтрую события по мере необходимости и создаю множество делегатов.

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

[[FSEventsListener instance] addListener:self forPath:somePath];

Мне просто нужно создать экземпляр FSEventListener при запуске приложения и выпустить его, когда приложение остановится. И мне просто нужно реализовать следующие 3 метода, которые будут вызываться автоматически:

-(void)fileWasAdded:(NSString *)file;
-(void)fileWasRemoved:(NSString *)file;
-(void)fileWasRenamed:(NSString *)oldFile to:(NSString *)newFile;

Если вас интересует исходный код этой небольшой утилиты, вы можете проверить здесь: http://blog.pcitron.fr/tools/macosx-imageviewer/ (утилита добавлена ​​в версии 0.8)

Я разработал его как часть небольшого средства просмотра изображений, чтобы пользовательский интерфейс синхронизировался с содержимым диска (он отображает количество изображений, содержащихся в каждом каталоге и т. д.). Исходный код доступен, а утилита находится в Utils/FSEventsListener.h. /.м.

И если по какой-то причине кто-то на самом деле загрузит приложение и взглянет на исходники, если вы найдете что-то полезное (улучшение производительности / функций и т. д.), не стесняйтесь оставить комментарий / написать письмо ^^

person Citron    schedule 05.09.2011
comment
на вашем сайте нет кнопки отправить на странице контактов, дайте мне ваш адрес электронной почты, я хочу задать вам вопрос. Спасибо:) - person Dima Deplov; 31.08.2013
comment
Я исправил контактную форму на своем сайте. Я не знаю, как отправить личное сообщение в StackOverflow (или даже если это возможно ^^) - person Citron; 02.09.2013
comment
@Citron я очень часто получаю kFSEventStreamEventFlagMustScanSubDirs. Есть ли способ решить эту проблему? - person Parag Bafna; 05.10.2014

На самом деле вы поднимаете две проблемы, связанные с FSEvents и переименованиями. 1. Файл переименован, и старые и новые имена файлов находятся в отслеживаемых деревьях каталогов. 2. Файл переименован и одно из имен отсутствует в отслеживаемых деревьях каталогов.

Вы решили (почти) первую проблему. Также необходимо предоставить вашему приложению средства, позволяющие узнать, о каких событиях сообщается в одной и той же группе событий FSEvent. Ваш метод определения того, что о двух переименованиях сообщается последовательно, работает только в том случае, если они относятся к одной и той же группе событий, о которых сообщается в течение одного и того же периода задержки. Если два события переименования типа 2 происходят одно за другим, но не входят в одну и ту же группу событий, сообщаемых в одной и той же группе задержки, они на самом деле не имеют ничего общего друг с другом, и вы ошибочно решите, что один файл был переименован в другой. .

Со вторым типом переименования можно справиться, просто отслеживая каждый каталог в системе с помощью рута, но это приведет к большому количеству ненужных событий. Вы можете определить, является ли «частичное» переименование результатом перемещения файла из отслеживаемого дерева каталогов или в отслеживаемое дерево каталогов, выполнив stat() для файла. Если stat() завершается с ошибкой 2, то файл был перемещен за пределы отслеживаемого каталога, и его можно рассматривать как удаленный. Если stat() завершается успешно, событие можно рассматривать так, как если бы файл был создан.

person MrNomis    schedule 09.06.2013
comment
У статистического подхода есть условие гонки: например, мог быть цепной ход, поэтому статистика на пути в середине последовательности обречена на провал. - person Heikki Toivonen; 16.08.2013