使用asyncio监视文件

时间:2014-10-16 21:17:47

标签: python python-3.x python-asyncio

我正在尝试使用Python's asyncio library确定一种观察文件外观的好方法。这是我到目前为止所提出的:

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

"""Watches for the appearance of a file."""

import argparse
import asyncio
import os.path


@asyncio.coroutine
def watch_for_file(file_path, interval=1):
    while True:
        if not os.path.exists(file_path):
            print("{} not found yet.".format(file_path))
            yield from asyncio.sleep(interval)
        else:
            print("{} found!".format(file_path))
            break


def make_cli_parser():
    cli_parser = argparse.ArgumentParser(description=__doc__)
    cli_parser.add_argument('file_path')
    return cli_parser


def main(argv=None):
    cli_parser = make_cli_parser()
    args = cli_parser.parse_args(argv)
    loop = asyncio.get_event_loop()
    loop.run_until_complete(watch_for_file(args.file_path))

if __name__ == '__main__':
    main()

我将其保存为watch_for_file.py,并可以使用

运行它
python3 watch_for_file.py testfile

在另一个shell会话中,我发出

touch testfile

结束循环。

是否有比使用此无限循环更优雅的解决方案和yield from asyncio.sleep()

4 个答案:

答案 0 :(得分:7)

嗯,在创建文件时,有更好的,特定于平台的通知方式。 Gerrat在他的评论中链接到一个用于Windows,而pyinotify可用于Linux。那些特定于平台的方法可能会被插入到asyncio中,但是你最终会编写一大堆代码来使它以独立于平台的方式工作,这可能不值得我们去检查单个文件的外观。如果你需要更复杂的文件系统观看,那么它可能值得追求。看起来可以调整pyinotify来添加插入Notifier事件循环的asyncio类的子类(已经有tornado和{{1}的类}),例如。

对于你的简单用例,我认为你的轮询无限循环方法很好,但如果你愿意的话,你也可以用事件循环来安排回调:

asyncore

我不确定这比无限循环更优雅。

修改

为了好玩,我使用def watch_for_file(file_path, interval=1, loop=None): if not loop: loop = asyncio.get_event_loop() if not os.path.exists(file_path): print("{} not found yet.".format(file_path)) loop.call_later(interval, watch_for_file, file_path, interval, loop) else: print("{} found!".format(file_path)) loop.stop() def main(argv=None): cli_parser = make_cli_parser() args = cli_parser.parse_args(argv) loop = asyncio.get_event_loop() loop.call_soon(watch_for_file, args.file_path) loop.run_forever() 编写了一个解决方案:

pyinotify

答案 1 :(得分:4)

Butter https://pypi.python.org/pypi/butter支持开箱即用的asyncio,BTW。

import asyncio
from butter.inotify import IN_ALL_EVENTS
from butter.asyncio.inotify import Inotify_async

@asyncio.coroutine
def watcher(loop):

    inotify = Inotify_async(loop=loop)
    print(inotify)
    wd = inotify.watch('/tmp', IN_ALL_EVENTS)

    for i in range(5):
        event = yield from inotify.get_event()
        print(event)

    inotify.ignore(wd)
    print('done')

    event = yield from inotify.get_event()
    print(event)

    inotify.close()
    print(inotify)

loop = asyncio.get_event_loop()
task = loop.create_task(watcher(loop))
loop.run_until_complete(task)

答案 2 :(得分:1)

根据documentation,您现在可以观看文件描述符。这应该可以帮助您用更少的代码解决这个问题。

答案 3 :(得分:0)

黄油真的很酷。另一种选择是 minotaur,它类似,但只实现了 inotify

async def main():
    with Inotify(blocking=False) as n:
        n.add_watch('.', Mask.CREATE | Mask.DELETE | Mask.MOVE)
        async for evt in n:
            print(evt)