使用 watchfiles 监控目录变更

简介: 使用 watchfiles 监控目录变更

在工作中难免会碰到这样的需求,监控指定目录,如果该目录下发生文件变更,那么进行一系列的处理。而如何监视一个目录,就是我们本次探讨的主题。

监视目录我们可以使用 watchfiles 模块,该模块不仅简单,而且性能也不错。主要原因是,和底层文件系统交互的代码是基于 Rust 编写的,所以性能是有保证的。

通过 pip install watchfiles 安装之后,我们来看看它的用法。

from watchfiles import watch
# 当前目录为 /Users/satori/Desktop/project
for change in watch("."):
    print(change)

我们执行此程序,会处于阻塞状态,并持续监听指定目录的变化。然后我们在当前目录创建几个文件,看看效果。

创建一个 data.txt 文本文件,程序输出如下:

{(<Change.added: 1>, '/Users/satori/Desktop/project/data.txt')}

返回的是一个集合,目前只涉及一个文件的变更,所以集合里面只有一个元素。而集合里面存储的都是元组,元组的第一个元素表示操作类型,总共有三种:分别是增加、修改和删除。

024b6a1d3fdda360ddd421c4fc9bdf0b.png

元组的第二个参数就是具体的文件路径,因此程序的输出就告诉我们,当前目录新增了一个 data.txt。

再创建一个 txt_files 目录,程序输出如下:

{(<Change.added: 1>, '/Users/satori/Desktop/project/txt_files')}

不管是目录文件还是文本文件,都属于文件,所以输出是一样的。如果想知道新增的到底是目录还是普通文件,那么还需要通过 os 模块检测一下。

我们在 txt_files 目录中创建一个 data.txt,程序输出如下:

{(<Change.added: 1>, '/Users/satori/Desktop/project/txt_files/data.txt')}

所以 watch 函数监听的不仅是指定目录,其内部的递归子目录也会一并监听。

问题来了,当前目录下存在一个 data.txt 文件和一个 txt_files 目录,而 txt_files 目录也存在一个 data.txt。那么如果将当前目录的 data.txt 移动到 txt_files 中,并同意覆盖,那么程序会输出什么呢?

{(<Change.deleted: 3>, '/Users/satori/Desktop/project/txt_files/data.txt'), 
 (<Change.added: 1>, '/Users/satori/Desktop/project/txt_files/data.txt'), 
 (<Change.deleted: 3>, '/Users/satori/Desktop/project/data.txt')}

此时输出的集合包含三个元组,因此该过程涉及到三次文件的变更。因为 txt_files 里面的文件被替换掉了,所以相当于先被删除、然后重新创建。而当前目录中的 data.txt 被移走了,因此相当于被删除了。

然后我们再通过 mkdir -p a/b/c 同时创建多级目录,程序输出如下:

{(<Change.added: 1>, '/Users/satori/Desktop/project/a/b/c'), 
 (<Change.added: 1>, '/Users/satori/Desktop/project/a/b'), 
 (<Change.added: 1>, '/Users/satori/Desktop/project/a')}

整个过程还是比较简单的,然后除了 watch 函数之外,还有一个 awatch。这两者的作用是一样的,参数也全部一样,只不过 awatch 需要和协程搭配,我们举个例子。

import sys
import asyncio
from asyncio import StreamReader
from watchfiles import awatch, Change
# 监视指定目录
async def watch_files(path):
    # awatch(...) 返回的是异步生成器,需要通过 async for 遍历
    async for change in awatch(path):
        print("-" * 20)
        # change 是一个集合,里面可能会涉及到多个文件的变更
        for item in change:
            if item[0] == Change.added:
                operation = "你增加了"
            elif item[0] == Change.modified:
                operation = "你修改了"
            else:
                operation = "你删除了"
            print(f"{operation} `{item[1]}`")
        print("\n")
# 读取命令行输入,但是注意:不可以使用 input 函数,因为它是同步阻塞调用
# 这种调用在协程当中是大忌,会阻塞整个线程,我们需要改造成异步模式
async def read_from_stdin():
    reader = asyncio.StreamReader()
    protocol = asyncio.StreamReaderProtocol(reader)
    loop = asyncio.get_running_loop()
    await loop.connect_read_pipe(lambda: protocol, sys.stdin)
    return reader
# read_from_stdin 函数的具体细节暂时不用太关注
# 只需要知道它能异步读取命令行即可,关于这方面的内容后续会介绍
# 然后定义主协程
async def main():
    # 监视当前目录
    asyncio.create_task(watch_files("."))
    # 创建读取器
    stdin_reader = await read_from_stdin()
    while True:
        # 从命令行读取输入
        command = await stdin_reader.readline()
        # 执行命令
        procs = await asyncio.create_subprocess_shell(command)
        await procs.wait()
loop = asyncio.get_event_loop()
try:
    loop.run_until_complete(main())
finally:
    loop.close()

来看一下效果:

f7526185e90fed4205b1e2516b8a1745.png

结果没有问题,文件的变化都检测出来了。然后补充一点:watch 和 awatch 可以同时监听多个目录,因为第一个参数是 *paths。

我们同时监听多个目录来测试一下,先在当前目录创建两个子目录:boy 和 girl,然后分别监视它们。

d543143d34405884cb8f47ad862b1d5e.png

输出正常,因此这两个函数可以监听任意多个目录。另外,由于目前监听的是当前目录的两个子目录,所以当前目录的文件变更就看不到了,因为它没有被监视。

cc3152eb22ae3485e9a9d40602d9e59a.png

以上就是这两个函数的基本用法,当然这两个函数还有其它参数:

efd0ab50b3fcf28feb43ef6e816b5004.png

这里简单介绍几个。

过滤器(watch_filter)

watchfiles 会监视目录的文件变化,但不是所有的文件都会记录。

ca070360171eb1b5051929f2af237fc9.png

watchfiles 有一个内置的过滤器,会将和业务无关的文件过滤掉,如果你还希望将其它格式的文件过滤掉,那么修改过滤器即可。

停止事件(stop_event)

监视文件的时候,迭代器是不会停止的,如果想自由控制它的结束,可以传递一个事件。

import asyncio
from watchfiles import awatch
async def watch_files(*paths, stop_event):
    async for _ in awatch(*paths, stop_event=stop_event):
        pass
    print("停止监视")
async def main():
    event = asyncio.Event()
    # 传递一个事件,准确的说,只要有 is_set 方法,任何对象都行
    asyncio.create_task(watch_files(".", stop_event=event))
    # 当 event.is_set() 为 True 的时候,停止监视
    print("is_set: ", event.is_set())
    await asyncio.sleep(3)  # sleep 3
    event.set()
    print("三秒后, is_set: ", event.is_set())
    # 等待子协程打印完毕
    await asyncio.sleep(0.1)
asyncio.run(main())
"""
is_set:  False
三秒后, is_set:  True
停止监视
"""


是否递归监视(recursive)

如果该参数为 True,那么会递归监视子目录,否则只监视顶层目录。

其它参数基本很少用,就不再赘述了,有兴趣可以自己了解一下。

相关文章
|
安全 应用服务中间件 nginx
Nginx限制IP访问只允许特定域名访问
为了我们的服务器安全,我们需要禁止直接使用 IP 访问我们的服务器,我们可以借助 Nginx 完成
2507 1
Nginx限制IP访问只允许特定域名访问
|
SQL 关系型数据库 MySQL
将MySQL 数据迁移到 PostgreSQL
将MySQL 数据迁移到 PostgreSQL 可以采用以下步骤: 安装 PostgreSQL 数据库:首先,需要安装 PostgreSQL 数据库。可以从官方网站(https://www.postgresql.org/)下载最新版本的 PostgreSQL,并根据官方指南进行安装。 创建 PostgreSQL 数据库:在 PostgreSQL 中创建与 MySQL 数据库相对应的数据库。可以使用 pgAdmin 或命令行工具(如 psql)来创建数据库。例如,如果在 MySQL 中有一个名为 &quot;mydb&quot; 的数据库,那么可以在 PostgreSQL 中创建一个具有相同名称的数据库。 导
6302 0
|
7月前
|
人工智能 算法 数据安全/隐私保护
La Suite Docs:开源协作文档平台,可私有部署的 Notion 替代方案
法国政府开源的企业级协作文档平台,GitHub 14.3k star。基于 Django+React 开发,支持实时协作、离线编辑、AI 辅助写作,可私有部署,是 Notion 的开源替代方案。转自:https://yunpan.plus/t/505-1-1
|
监控 Java Linux
开源流程引擎Camunda
开源流程引擎Camunda
|
Ubuntu Python
【Python】报错ModuleNotFoundError: No module named ‘XXX‘
【Python】报错ModuleNotFoundError: No module named ‘XXX‘
|
10月前
|
监控 Linux 数据安全/隐私保护
Python实现Word转PDF全攻略:从入门到实战
在数字化办公中,Python实现Word转PDF自动化,可大幅提升处理效率,解决格式兼容问题。本文详解五种主流方案,包括跨平台的docx2pdf、Windows原生的pywin32、服务器部署首选的LibreOffice命令行、企业级的Aspose.Words,以及轻量级的python-docx+pdfkit组合。每种方案均提供核心代码与适用场景,并涵盖中文字体处理、表格优化、批量进度监控等实用技巧,助力高效办公自动化。
2022 0
|
负载均衡 网络协议 Linux
LVS,软负载均衡
LVS(Linux Virtual Server)是一项广泛应用的负载均衡技术,由章文嵩博士于1998年发起,自Linux 2.4.24版本起成为官方内核的一部分。LVS通过四层负载均衡技术实现高性能、高可用的服务器集群,支持多种调度算法和工作模式(如D-NAT、full-NAT、IP隧道、DR),适用于HTTP、数据库等应用。相比7层负载均衡器(如Nginx、HAProxy),LVS具有更高的并发处理能力和更低的资源消耗,适合大规模流量分发。本期文章详细介绍了LVS的工作原理、优势与不足,并对比了常见的负载均衡产品,帮助读者根据具体需求选择合适的解决方案。
2561 6
LVS,软负载均衡
Python 代码从 `.env` 文件中读取环境变量
这篇文章介绍了如何在Python项目中使用`python-dotenv`库从`.env`文件读取环境变量的详细步骤,包括安装库、创建`.env`文件、在代码中加载和读取环境变量。
|
关系型数据库 Linux 数据库
PostgreSQL 入门指南:安装、配置与基本命令
本文从零开始,详细介绍如何在 Windows、Linux 和 macOS 上安装和配置 PostgreSQL,涵盖30+个实操代码示例。内容包括安装步骤、配置远程访问和用户权限、基础数据库操作命令(如创建表、插入和查询数据),以及常见问题的解决方案。通过学习,你将掌握 PostgreSQL 的基本使用方法,并为后续深入学习打下坚实基础。
15575 1
|
自然语言处理 数据可视化 API
Qwen系列模型+GraphRAG/LightRAG/Kotaemon从0开始构建中医方剂大模型知识图谱问答
本文详细记录了作者在短时间内尝试构建中医药知识图谱的过程,涵盖了GraphRAG、LightRAG和Kotaemon三种图RAG架构的对比与应用。通过实际操作,作者不仅展示了如何利用这些工具构建知识图谱,还指出了每种工具的优势和局限性。尽管初步构建的知识图谱在数据处理、实体识别和关系抽取等方面存在不足,但为后续的优化和改进提供了宝贵的经验和方向。此外,文章强调了知识图谱构建不仅仅是技术问题,还需要深入整合领域知识和满足用户需求,体现了跨学科合作的重要性。

热门文章

最新文章