我正在尝试使用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()
?
答案 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)