python pyinotify для мониторинга указанных файлов суффиксов в каталоге

Я хочу отслеживать каталог, и в каталоге есть подкаталоги, а в подкаталоге есть несколько файлов с .md. (возможно, есть еще какие-то файлы, например *.swp...)

Я хочу отслеживать только файлы .md, я прочитал документ, и там только ExcludeFilter, а в выпуске: https://github.com/seb-m/pyinotify/issues/31 говорит, что фильтровать можно только каталоги, но не файлы.

Теперь я фильтрую process_* функций, чтобы проверить event.name на fnmatch.

Итак, если я хочу отслеживать только указанные файлы суффиксов, есть ли лучший способ? Спасибо.

Это основной код, который я написал:

!/usr/bin/env python                                                                                                                                
# -*- coding: utf-8 -*-

import pyinotify                                                                    
import fnmatch                                                                      

def suffix_filter(fn):                                                              
    suffixes = ["*.md", "*.markdown"]                                                                                                                
    for suffix in suffixes:                                                         
        if fnmatch.fnmatch(fn, suffix):                                             
            return False                                                            
    return True                                                                     

class EventHandler(pyinotify.ProcessEvent):                                         
    def process_IN_CREATE(self, event):                                             
        if not suffix_filter(event.name):                                           
            print "Creating:", event.pathname                                       

    def process_IN_DELETE(self, event):                                             
        if not suffix_filter(event.name):                                           
            print "Removing:", event.pathname                                       

    def process_IN_MODIFY(self, event):                                             
        if not suffix_filter(event.name):                                           
            print "Modifing:", event.pathname                                       

    def process_default(self, event):                                               
        print "Default:", event.pathname

person Tanky Woo    schedule 19.08.2013    source источник


Ответы (3)


Я думаю, что у вас в основном правильная идея, но ее можно было бы реализовать проще.

В классе ProcessEvent в модуле pyinotify уже есть хук, который можно использовать для фильтрации обработки событий. Он указывается с помощью необязательного аргумента ключевого слова pevent, заданного при вызове конструктора, и сохраняется в атрибуте self.pevent экземпляра. Значение по умолчанию — None. Это значение используется в методе __call__() класса, как показано в следующем фрагменте из исходного файла pyinotify.py:

def __call__(self, event):
    stop_chaining = False
    if self.pevent is not None:
        # By default methods return None so we set as guideline
        # that methods asking for stop chaining must explicitly
        # return non None or non False values, otherwise the default
        # behavior will be to accept chain call to the corresponding
        # local method.
        stop_chaining = self.pevent(event)
    if not stop_chaining:
        return _ProcessEvent.__call__(self, event)

Таким образом, вы можете использовать его, чтобы разрешать события только для файлов с определенными суффиксами (также известными как расширения) примерно так:

SUFFIXES = {".md", ".markdown"}

def suffix_filter(event):
    # return True to stop processing of event (to "stop chaining")
    return os.path.splitext(event.name)[1] not in SUFFIXES

processevent = ProcessEvent(pevent=suffix_filter)
person martineau    schedule 19.08.2013
comment
Ранее я прокомментировал, что не могу заставить это работать, но теперь я понял. Вам нужно отредактировать SUFFIXES и удалить * (иначе он никогда не совпадет) и вызвать splitext для fn.name, потому что вызываемый pevent принимает Event в качестве своего параметра. +1, лучше, чем мое решение, и я действительно пытался решить это с помощью pevent, но по какой-то причине не смог заставить его работать. - person Paulo Almeida; 19.08.2013
comment
Спасибо большое, этот способ очень классный! В коде небольшая ошибка. при использовании suffix_filter в качестве обратного вызова для pevent аргументом suffix_filter является event, поэтому он должен быть os.path.splitext(fn.name)[1] - person Tanky Woo; 19.08.2013
comment
Tanky, @Paulo: Спасибо, что указали на ошибки в коде. По возможности я не публикую непроверенные материалы, но в данном случае не могу, потому что в моей ОС нет inotify. - person martineau; 19.08.2013

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

Вы должны переместить суффиксы соответствия из своей функции, чтобы компилятор строил их только один раз:

EXTS = set([".md", ".markdown"])

Я сделал их набором, чтобы вы могли сделать более эффективное совпадение:

def suffix_filter(fn):
  ext = os.path.splitext(fn)[1]
  if ext in EXTS:
    return False
  return True

Я только предполагаю, что os.path.splitext и наборный поиск быстрее, чем итеративный fnmatch, но это может быть неверно для вашего действительно небольшого списка расширений - вы должны проверить это.

(Примечание: я отразил ваш код выше, где вы возвращаете False при сопоставлении, но я не уверен, что это то, что вы хотите - это, по крайней мере, не очень понятно для тех, кто читает ваш код)

person Nick Bastin    schedule 19.08.2013
comment
Танкий ты. Раньше я не знал, что операция in в set быстрее, чем list, ссылка: stackoverflow.com/questions/ 2831212/python-sets-vs-lists . О вашем примечании: я хочу отфильтровать суффикс, не соответствующий указанному, поэтому при фильтрации я возвращаю True, есть ли способ сделать это понятным? - person Tanky Woo; 19.08.2013

Вы можете использовать метод __call__ для ProcessEvent, чтобы централизовать вызов suffix_filter:

class EventHandler(pyinotify.ProcessEvent):
    def __call__(self, event):
        if not suffix_filter(event.name):
            super(EventHandler, self).__call__(event)

    def process_IN_CREATE(self, event):
        print "Creating:", event.pathname

    def process_IN_DELETE(self, event):
        print "Removing:", event.pathname

    def process_IN_MODIFY(self, event):
        print "Modifying:", event.pathname
person Paulo Almeida    schedule 19.08.2013