Мониторинг событий файловой системы с использованием Python без других библиотек низкого уровня - PullRequest
1 голос
/ 21 октября 2011

Отлично, мне нужно отлавливать события удаления и добавления файлов в какой-то каталог на ОС Linux.Я нашел такие библиотеки, как inotify и оболочки Python для них, но если я хочу использовать чистый код Python, я должен наблюдать за выводом os.listdir(path) каждую секунду, или есть ли способы выполнить такую ​​задачу?

1 Ответ

1 голос
/ 21 октября 2011

Источник: http://code.activestate.com/recipes/215418-watching-a-directory-tree-on-unix/

Функция watch_directories () берет список путей и вызываемый объект, а затем многократно просматривает деревья каталогов, укорененных в этих путях, отслеживая файлы, которые были удалены или имеютвремя модификации изменилось.Затем вызываемому объекту передаются два списка, содержащие файлы, которые были изменены, и файлы, которые были удалены.

from __future__ import nested_scopes

import os, time

def watch_directories (paths, func, delay=1.0):
    """(paths:[str], func:callable, delay:float)
    Continuously monitors the paths and their subdirectories
    for changes.  If any files or directories are modified,
    the callable 'func' is called with a list of the modified paths of both
    files and directories.  'func' can return a Boolean value
    for rescanning; if it returns True, the directory tree will be
    rescanned without calling func() for any found changes.
    (This is so func() can write changes into the tree and prevent itself
    from being immediately called again.)
    """

    # Basic principle: all_files is a dictionary mapping paths to
    # modification times.  We repeatedly crawl through the directory
    # tree rooted at 'path', doing a stat() on each file and comparing
    # the modification time.  

    all_files = {}
    def f (unused, dirname, files):
        # Traversal function for directories
        for filename in files:
            path = os.path.join(dirname, filename)

            try:
                t = os.stat(path)
            except os.error:
                # If a file has been deleted between os.path.walk()
                # scanning the directory and now, we'll get an
                # os.error here.  Just ignore it -- we'll report
                # the deletion on the next pass through the main loop.
                continue

            mtime = remaining_files.get(path)
            if mtime is not None:
                # Record this file as having been seen
                del remaining_files[path]
                # File's mtime has been changed since we last looked at it.
                if t.st_mtime > mtime:
                    changed_list.append(path)
            else:
                # No recorded modification time, so it must be
                # a brand new file.
                changed_list.append(path)

            # Record current mtime of file.
            all_files[path] = t.st_mtime

    # Main loop
    rescan = False
    while True:
        changed_list = []
        remaining_files = all_files.copy()
        all_files = {}
        for path in paths:
            os.path.walk(path, f, None)
        removed_list = remaining_files.keys()
        if rescan:
            rescan = False
        elif changed_list or removed_list:
            rescan = func(changed_list, removed_list)

        time.sleep(delay)

if __name__ == '__main__':
    def f (changed_files, removed_files):
        print changed_files
        print 'Removed', removed_files

    watch_directories(['.'], f, 1)

Этот рецепт полезен, если вы хотите каким-либо образом отправить задания демону, ноне хочу использовать какой-либо механизм IPC, такой как сокеты или каналы.Вместо этого демон может сидеть и наблюдать каталог отправки, а задания можно отправить, перетащив файл или каталог в каталог отправки.

Блокировка не учитывается.Сама функция watch_directories () на самом деле не нуждается в блокировке;если он пропустит модификацию на одном проходе, он заметит это на следующем проходе.Однако, если задания записываются непосредственно в наблюдаемый каталог, вызываемый объект может запускаться, пока файл задания наполовину записан.Чтобы решить эту проблему, вы можете использовать файл блокировки;вызываемый должен получить блокировку при запуске, а отправители должны получить блокировку, когда они хотят добавить новую работу.Более простой подход - полагаться на то, что системный вызов rename () является атомарным: записать задание во временный каталог, который не отслеживается, и как только файл будет завершен, используйте os.rename (), чтобы переместить его в каталог отправки.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...