Python Watchdog:高效的文件系统监控
1. 写在前面
在软件开发中,有时候需要通过 Python 去监听指定区域文件或目录的创建、修改,或者删除,从而引发特定的事件处理。本篇博客为你介绍第三方模块 Watchdog 实现对文件事件的监控。
公众号: 滑翔的纸飞机
2. Watchdog
2.1 什么是 Watchdog?
用于监视文件系统事件的 Python API 和 shell 实用程序。
**项目地址:**https://pypi.org/project/watchdog/
**最新版本:**Watchdog 3.0.0 适用于 Python 3.7+
**安装:**需要运行以下命令进行安装(确保使用的是 Python 3.7+):
pip install watchdog
2.2 官方快速入门示例
以下示例程序:将以递归方式监视当前目录文件系统变更,并简单地将它们输出到控制台;
import sys
import logging
from watchdog.observers import Observer
from watchdog.events import LoggingEventHandlerif __name__ == "__main__":# 设置日志信息格式logging.basicConfig(level=logging.INFO,format='%(asctime)s - %(message)s',datefmt='%Y-%m-%d %H:%M:%S')# 要监控的目录路径path = sys.argv[1] if len(sys.argv) > 1 else '.'# 创建一个日志事件处理程序event_handler = LoggingEventHandler()# 创建一个观察者对象observer = Observer()# 声明一个定时任务observer.schedule(event_handler, path, recursive=True)# 启动定时任务observer.start()try:while observer.is_alive():observer.join(1)finally:observer.stop()observer.join()
输出: 跟踪目录变更事件,通过日志输出变更记录。
例如: 创建 test > 1.txt 控制台输出:
2023-10-19 00:56:18 - Created directory: /Users/demo/2023/10/watchdog/test
2023-10-19 00:56:18 - Modified directory: /Users/demo/2023/10/watchdog
2023-10-19 00:56:27 - Created file: /Users/demo/2023/10/watchdog/test/1.txt
2023-10-19 00:56:27 - Modified directory: /Users/demo/2023/10/watchdog/test
2.3 Event Handler 和 Observer
Watchdog 的主要实现或者可以说 Watchdog 的构件是基于以下类:
- Observer:观察者,用于监视目录并将调用分派给事件处理程序;
- Event handler: 文件系统事件和事件处理程序;
说白了,Observer 监控目录,触发 Event handler 针对事件做出响应;
导入方式:
from watchdog.observers import Observer
from watchdog.events import FileSystemEventHandler
2.3.1 Event handler
以下是Watchdog中默认提供的4个事件处理类:
- FileSystemEventHandler:文件,事件处理器的基类,用于处理事件;
- PatternMatchingEventHandler:模式匹配文件;
- RegexMatchingEventHandler:正则匹配文件;
- LoggingEventHandler:记录日志。
有关处理程序的更多详情,请参阅此链接
通过扩展 Watchdog 提供的默认事件处理程序类,实现自定义的函数来处理修改、创建、删除和移动事件。还可以覆盖 FileSystemEventHandler 中的函数(以下函数),因为其他事件处理类都继承自该类。
**on_any_event(event):**捕获所有事件处理程序;
**on_created(event):**在创建文件或目录时调用;
**on_deleted(event):**删除文件或目录时调用;
**on_modified(event):**当文件或目录被修改时调用;
**on_moved(event):**在移动或重命名文件或目录时调用;
**on_closed(event):**文件已关闭时调用;
**on_opened(event):**打开文件时调用;
每个函数都有一个名为 event 的输入参数,其中包含以下变量:
- event_type:字符串形式的事件类型(“moved”、“deleted”、“created”、“modified”、“closed”、“opened”),默认为 “无”;
- is_directory:True:表示事件针对目录;
- src_path:触发此事件的文件系统对象的源路径;
2.3.2 Observer
如果大家熟悉设计模式,那么 Watchdog 就遵循观察设计模式。因此,每个观察者都会有事件,如果文件或目录有任何变化,它就会查看并显示变化。
Observer,观察目录,针对事件调用处理程序,也可以直接导入特定平台的类,并用它代替 Observer
2.3.3 回顾上文简单示例
通过上述介绍,对 Event handler 和 Observer有一个简单的理解,现在我们回过头继续来看官方示例:
import sys
import logging
from watchdog.observers import Observer
from watchdog.events import LoggingEventHandlerif __name__ == "__main__":# 设置日志信息格式logging.basicConfig(level=logging.INFO,format='%(asctime)s - %(message)s',datefmt='%Y-%m-%d %H:%M:%S')# 要监控的目录路径path = sys.argv[1] if len(sys.argv) > 1 else '.'# 创建一个日志事件处理程序event_handler = LoggingEventHandler()# 创建一个观察者对象observer = Observer()# 声明一个定时任务observer.schedule(event_handler, path, recursive=True)# 启动定时任务observer.start()try:while observer.is_alive():observer.join(1)finally:observer.stop()observer.join()
(1)event_handler = LoggingEventHandler(): 创建一个日志事件处理程序;
(2)observer = Observer():创建一个观察者对象;
(3)observer.schedule(event_handler, path, recursive=True):声明一个定时任务,传入事件处理程序、监控路径、以及是否递归子目录;
(4)observer.start():启动定时任务;
进一步分析下:
schedule(self, event_handler, path, recursive=False):
该方法用于监视 path 路径,并调用给定的事情 event_handler 。
参数 recursive 表示是否递归子目录,即监听子目录,默认为 False。
start():
启动线程,这里开启了新的守护线程,主程序如果结束, 该线程也会停止。
每个线程对象只能调用1次,它安排对象的 run() 方法在单独的控制线程中调用,如果在同一线程对象上多次调用此方法将引发 RuntimeError。
2.4. 理解和使用
基于上述关键概念介绍以及官方示例,自己实现一个文件事件监听;
在本例中,使用 FileSystemEventHandler 事件类。对一个文件夹设置监视,并在有文件产生时触发另一个函数。处理完成后,将把文件移到另一个文件夹。
(1)首先,你需要创建一个继承自 FileSystemEventHandler 事件处理类,并创建一个观察者和自定义的事件处理程序实例。
from watchdog.observers import Observer
from watchdog.events import FileSystemEventHandlerclass MyHandler(FileSystemEventHandler):passobserver = Observer()
event_handler = MyHandler()
(2)创建一个定时任务,传入以下参数
- event_handler:刚创建的处理程序对象;
- path:要跟踪的文件夹路径;
- recursive:是否递归子目录;
observer.schedule(event_handler, path='./input_files', recursive=True)
(3) observer.start() - 启动任务,等待目录产生事件,触发事件处理程序中的代码。
(4) observer.stop() - 该函数将清理资源。
(5) 最后用 observer.join() 结束,因为我们在这里使用的是多线程概念。join() 将连接多个线程,直到调用 join 方法的线程终止。
observer.start()
try:while True:time.sleep(300)
except KeyboardInterrupt:observer.stop()
observer.join()
接下去,自定义事件处理类:MyHandler
在这个示例中,我将检查是否有文件上传到所跟踪的文件夹中。为此,我可以使用 on_created(event):
def create_directory(file_path=None):# 以'年-月-日'的格式获取当前日期current_date = datetime.now().strftime('%Y-%m-%d')# 创建一个包含当前日期的文件夹folder_path = f'{file_path}/{current_date}'if not os.path.exists(folder_path):os.makedirs(folder_path)return folder_pathelse:return folder_pathclass MyHandler(FileSystemEventHandler):def on_created(self, event):dir_path = event.src_path.split('/input_files')processed_files = f'{dir_path[0]}/processed_files'child_processed_dir = create_directory(file_path=processed_files)if event:print("file created:{}".format(event.src_path))# 这里调用其他处理函数main(file_name=event.src_path)file_name = event.src_path.split('/')[-1]destination_path = f'{child_processed_dir}/{file_name}'# 将文件移动到其他目录shutil.move(event.src_path, destination_path)print("file moved:{} to {}".format(event.src_path, destination_path))
在上面的示例中,我使用函数 create_directory() 来检查目标路径中是否有当前日期的文件夹,否则就创建相同的文件夹。
然后,在其他 python 脚本函数 main() 中做了一些处理后,使用相同的路径作为目标路径来移动文件
下面是最终代码:my_event_handler.py
from watchdog.observers import Observer
from watchdog.events import FileSystemEventHandler
import shutil
import time
import os
from datetime import datetime
from watchdog_fileobserver import maindef create_directory(file_path=None):# 以'年-月-日'的格式获取当前日期current_date = datetime.now().strftime('%Y-%m-%d')# 创建一个包含当前日期的文件夹folder_path = f'{file_path}/{current_date}'if not os.path.exists(folder_path):os.makedirs(folder_path)return folder_pathelse:return folder_pathclass MyHandler(FileSystemEventHandler):def on_created(self, event):dir_path = event.src_path.split('/input_files')processed_files = f'{dir_path[0]}/processed_files'child_processed_dir = create_directory(file_path=processed_files)if event:print("file created:{}".format(event.src_path))# 这里调用其他处理函数main(file_name=event.src_path)file_name = event.src_path.split('/')[-1]destination_path = f'{child_processed_dir}/{file_name}'shutil.move(event.src_path, destination_path)print("file moved:{} to {}".format(event.src_path, destination_path))if __name__ == "__main__":observer = Observer()event_handler = MyHandler()observer.schedule(event_handler, path='./input_files', recursive=True)observer.start()try:while True:time.sleep(300)except KeyboardInterrupt:observer.stop()observer.join()
watchdog_fileobserver.py:
import csvdef read_csv_file(file_name):try:with open(f"{file_name}", 'r') as file:csvreader = csv.DictReader(file)for row in csvreader:print(row)return csvreaderexcept Exception as e:passdef main(file_name=None):if file_name:dict_data = read_csv_file(file_name)print("Process completed")else:print("Invalid file path")
在这种情况下,需要等待文件上传,然后执行所需的操作。为此,你可以在事件函数中添加以下代码:
def on_created(self, event):file_size = -1while file_size != os.path.getsize(event.src_path):file_size = os.path.getsize(event.src_path)print(file_size)time.sleep(1)### OR ###def on_created(self, event):file = Nonewhile file is None:try:file = open(event.src_path)except OSError:logger.info('Waiting for file transfer....')time.sleep(1)continue
验证:
脚本所在路径下,创建用于监听目录 input_files, 在该目录下创建一个文件,控制台输出:
file created:/Users/demo/2023/10/watchdog/input_files/text.txt
Process completed
file moved:/Users/demo/2023/10/watchdog/input_files/text.txt to /Users/demo/2023/10/watchdog/processed_files/2023-10-20/text.txt
目录如下:
.
├── input_files
├── my_event_handler.py
├── processed_files
│ └── 2023-10-20
│ └── text.txt
└── watchdog_fileobserver.py
2.5. Watchdog 使用案例
2.5.1 忽略子目录或只包含模式匹配文件的情况
如果要忽略某个目录中的某些文件,可以使用最简单的方法之一,即使用 PatternMatchingEventHandler
在文件 my_event_handler.py 中,修改 MyHandler 中的继承类(PatternMatchingEventHandler),如下所示:
class MyHandler(PatternMatchingEventHandler):........if __name__ == "__main__":event_handler = MyHandler(patterns=["*.csv", "*.pdf"],ignore_patterns=[],ignore_directories=True)........
2.5.2 使用 Celery 来启动/停止 Watchdog
可以使用下面的示例来实现 Watchdog。不过,这个示例只是一个关于如何将 celery 集成到Watchdog 中的想法。
from celery import Celery
from watchdog.observers import Observer
from watchdog.events import PatternMatchingEventHandler
import os
import timeapp = Celery('celery_ex.celery_apptask_ex', broker='redis://localhost:6379/0')@app.task
def process_file(file_path):# do something with the filewith open(file_path, 'r') as f:print(f.read())class MyHandler(PatternMatchingEventHandler):def on_created(self, event):file_size = -1while file_size != os.path.getsize(event.src_path):file_size = os.path.getsize(event.src_path)print(file_size)time.sleep(1)if event:print("file created:{}".format(event.src_path))# call function hereprocess_file.apply_async(args=(event.src_path,))if __name__ == "__main__":observer = Observer()event_handler = MyHandler(patterns=["*.csv", "*.pdf"],ignore_patterns=[],ignore_directories=True)observer.schedule(event_handler, path='./input_files', recursive=True)observer.start()try:while True:time.sleep(1)except KeyboardInterrupt:observer.stop()observer.join()
此示例需要 redis、celery 支持;
2.5.3 监控目录变化
观察者(observer)可以设置指定目录及其所有子目录,在文件或目录创建、删除或修改时调用相应的方法(on_created、on_deleted 或 on_modified),观察者以无限循环的方式运行,可以被键盘中断打断。
import time
from watchdog.observers import Observer
from watchdog.events import FileSystemEventHandlerclass EventHandler(FileSystemEventHandler):def on_created(self, event):if event.is_directory:print("Directory created:", event.src_path)else:print("File created:", event.src_path)def on_deleted(self, event):if event.is_directory:print("Directory deleted:", event.src_path)else:print("File deleted:", event.src_path)def on_modified(self, event):if event.is_directory:print("Directory modified:", event.src_path)else:print("File modified:", event.src_path)event_handler = EventHandler()
observer = Observer()
observer.schedule(event_handler, "/path/to/dir", recursive=True)
observer.start()try:while True:time.sleep(1)
except KeyboardInterrupt:observer.stop()
observer.join()
2.5.4 使用线程和多进程执行 Watchdog 来启动独立进程
可以运行 Watchdog,使用线程和多进程并行处理多个文件。下面是一个相同的示例:
from watchdog.observers import Observer
from watchdog.events import PatternMatchingEventHandler
import os
import ntpath
import time
import optparse
import multiprocessing
import threading
from collections import OrderedDictlock = threading.RLock()def process_function(get_event, event_dict):print(f"Process started for event: {get_event}")dir_path = ntpath.abspath(get_event)file_name = ntpath.basename(get_event)if len(get_event) > 0:your_own_function()do something....class Handler(PatternMatchingEventHandler):def __init__(self, queue):PatternMatchingEventHandler.__init__(self, patterns=['*.csv'],ignore_patterns=[],ignore_directories=True)self.queue = queuedef on_created(self, event):# logger.info(f"Wait while the transfer of the file is finished before processing it")# file_size = -1# while file_size != os.path.getsize(event.src_path):# file_size = os.path. getsize(event.src_path)# time.sleep(1)file = Nonewhile file is None:try:file = open(event.src_path)except OSError:logger.info('Waiting for file transfer')time.sleep(5)continueself.queue.put(event.src_path)def on_modified(self, event):passdef start_watchdog(watchdog_queue, dir_path):logger.info(f"Starting Watchdog Observer\n")event_handler = Handler(watchdog_queue)observer = Observer()observer.schedule(event_handler, dir_path, recursive=False)observer.start()try:while True:time.sleep(1)except Exception as error:observer.stop()logger.error(f"Error: {str(error)}")observer.join()if __name__ == '__main__':dir_path = r'//file_path/'watchdog_queue = Queue()logger.info(f"Starting Worker Thread")worker = threading.Thread(target=start_watchdog, name="Watchdog",args=(watchdog_queue, dir_path), daemon=True)worker.start()mp = Manager()event_dict = mp.dict()while True:if not watchdog_queue.empty():logger.info(f"Is Queue empty: {watchdog_queue.empty()}")pool = Pool()pool.apply_async(process_function, (watchdog_queue.get(), event_dict))else:time.sleep(1)
2.5.5 在 Watchdog 中进行日志记录
要记录事件,可以创建一个继承自 FileSystemEventHandler 类的自定义事件处理程序类,并重写与要记录的事件相对应的方法。
下面举例说明如何使用 Watchdog 库记录文件创建和修改事件:
import logging
from watchdog.observers import Observer
from watchdog.events import FileSystemEventHandlerclass LogEventHandler(FileSystemEventHandler):def on_created(self, event):if not event.is_directory:logging.info(f"File created: {event.src_path}")def on_modified(self, event):if not event.is_directory:logging.info(f"File modified: {event.src_path}")logging.basicConfig(filename='watchdog.log', level=logging.INFO, format='%(asctime)s - %(message)s')
event_handler = LogEventHandler()
observer = Observer()
observer.schedule(event_handler, "/path/to/", recursive=True)
observer.start()try:while True:time.sleep(1)
except KeyboardInterrupt:observer.stop()
observer.join()
3. 最后
无论你是在一个需要跟踪多个文件的大型项目中工作,还是只想关注单个文件的任务,Watchdog 库都能满足你的需求。
感谢您花时间阅读文章
关注公众号不迷路
相关文章:
Python Watchdog:高效的文件系统监控
1. 写在前面 在软件开发中,有时候需要通过 Python 去监听指定区域文件或目录的创建、修改,或者删除,从而引发特定的事件处理。本篇博客为你介绍第三方模块 Watchdog 实现对文件事件的监控。 公众号: 滑翔的纸飞机 2. Watchdog 2…...

C++中多态的原理【精华】
虚函数表 通过一道题我们先感受一下编译器针对多态的处理 #include <iostream> using namespace std;class Base { public:virtual void Func1(){cout << "Func1()" << endl;} private:int _b 1;char _c };int main() {cout << sizeof(B…...

亿赛通电子文档安全管理系统 Update.jsp SQL注入
目录 0x01 漏洞介绍 0x02 影响产品 0x03 语法特征 0x04 漏洞复现页面 0x05 漏洞修复建议 0x01 漏洞介绍 亿赛通电子文档安全管理系统是国内最早基于文件过滤驱动技术的文档加解密产品之一,保护范围涵盖终端电脑(Windows、Mac、Linux系统平台&#…...

神经网络中的反向传播:综合指南
塔曼纳 一、说明 反向传播是人工神经网络 (ANN) 中用于训练深度学习模型的流行算法。它是一种监督学习技术,用于调整网络中神经元的权重,以最小化预测输出和实际输出之间的误差。 在神经网络中,反向传播是计算损失函数…...

协同创新、奔赴未来——“华为云杯”2023人工智能创新应用大赛华丽谢幕
9月27日,在苏州工业园区管理委员会、华为云计算技术有限公司的指导下,由SISPARK(苏州国际科技园)、华为(苏州)人工智能创新中心联合主办,东北大学工业智能与系统优化国家级前沿科学中心、浙江大…...
介绍Node.js中fs模块 代码和注释。
Node.js中的fs模块提供了一些用于文件系统操作的API,包括文件读写、目录操作等。 读取文件 使用fs.readFile()方法可以读取文件内容。该方法的第一个参数是文件路径,第二个参数是可选的选项对象,第三个参数是回调函数。回调函数的第一个参数…...

【QT 读取JSON】 深入浅出 使用QT内置的QJson模块解析Json文件 匠心之作
目录 0 引言1 Json数据分析2 解析Json数据 🙋♂️ 作者:海码007📜 专栏:QT专栏💥 标题:【QT 读取JSON】 使用QT内置的QJson模块解析Json文件❣️ 寄语:人生的意义或许可以发挥自己全部的潜力&…...

初识javaweb2 tomcat
如果是tomcat启动成功却无法通过localhost:8080进入页面,先去查看是否是端口号被占用, 再用命令中断占用的进程,如果简单的命令窗口无法中断,切换到管理员身份运行即可 netstat -ano|findstr "8080" 查看那个进程占用了…...
使用OPENROWSET :在一个数据库中查询另一个数据库的数据
当你需要在一个数据库中查询另一个数据库的数据时,SQL Server提供了多种方法来实现这一目标。一种常见的方法是使用链接服务器(Linked Server),另一种方法是使用 OPENROWSET 函数。本篇博客将重点介绍如何使用 OPENROWSET 函数在当…...
基于STM32设计的智慧农业管理系统(ESP8266+腾讯云微信小程序)
一、项目介绍 基于STM32设计的智慧农业控制系统(ESP8266+腾讯云微信小程序) 1.1 项目背景 随着人们对食品安全和生态环境的日益重视,智慧农业逐渐成为一个备受关注的领域。智能化管理可以提高农业生产效率,减少资源浪费,改善生态环境。因此,基于物联网技术的智慧农业管理系…...

Flutter视图原理之三棵树的建立过程
目录 三棵树的关系树的构建过程1.updateChild函数(element的复用)2.inflateWidget函数3.mount函数3.1 componentElement的实现3.2 RenderObjectElement的实现3.2.1 attachRenderObject函数 4.performRebuild函数 总结三棵树创建流程 三棵树的关系 Flutt…...
详细解析冒泡排序,JS如何基本实现的。
目录 冒泡排序是什么: 使用冒泡排序是为了什么: DEMO示例: 冒泡排序是什么: 冒泡排序(Bubble Sort)是一种简单的比较排序算法,它通过多次遍历待排序的元素,比较相邻元素的大小,如果它们的顺序不正确就交换它们&…...
如何消除CSDN博文代码中自动添加的行号
哪里有自定义目录标题 编写CSDN博文,使用代码块的linux命令行,预览时没有代码行号,但发布文章后自动添加了行号。 git clone https://github.com/mikel-brostrom/yolo_tracking.git cd yolo_tracking pip install -v -e .为什么预览和发布的…...

定制效果在线定制印刷系统源码 DIY在线定制系统源码 云印刷定制系统源码手机、PC端实时互通
支持各类产品的在线定制,无论是水杯雨伞U盘还是T恤衬衫四件套,均可轻松进行定制 独创制作间概念,同一套模板可以重复对应不同制作间 手机、PC端实时互通,客户可通过任意途径进行图片上传、编辑,一方修改另一方即时可见…...
算法|每日一题|同积元组|哈希统计
1726.同积元组 原题地址: 力扣每日一题:同积元组 给你一个由 不同 正整数组成的数组 nums ,请你返回满足 a * b c * d 的元组 (a, b, c, d) 的数量。其中 a、b、c 和 d 都是 nums 中的元素,且 a ! b ! c ! d 。 class Solution …...

最新AI创作系统ChatGPT网站H5源码V2.6.4+搭建部署教程+支持GPT4.0+支持ai绘画(Midjourney)/支持Prompt预设应用
一、AI创作系统 SparkAi创作系统是基于OpenAI很火的ChatGPT进行开发的Ai智能问答系统AI绘画系统,支持OpenAI GPT全模型国内AI全模型。本期针对源码系统整体测试下来非常完美,可以说SparkAi是目前国内一款的ChatGPT对接OpenAI软件系统。那么如何搭建部署…...

最新!两步 永久禁止谷歌浏览器 Google Chrome 自动更新
先放效果图: CSDN这个问题最火的大哥的用了没用 像他这样连浏览器都打不开 为什么要禁止chrome自动更新 看到很多搞笑的大哥,说为啥要禁止; 我觉得最大的原因就是chromedriver跟不上chrome的自动更新,导致我们做selenium爬虫的…...
在Java中线程和进程的区别
在Java中,线程和进程的区别与一般的操作系统环境下类似,但在Java语言层面上也有一些特点。下面是在Java中线程和进程的区别: 定义:在Java中,进程是指一个正在运行的应用程序实例,而线程是进程中的执行单元。…...

【高危安全通告】Oracle 10月月度安全漏洞预警
近日,安全狗应急响应中心关注到Oracle官方发布安全公告,共披露出在Oracle Weblogic中存在的6个高危漏洞。 漏洞描述 CVE-2023-22069:Oracle Weblogic 远程代码执行漏洞 Oracle WebLogic Server存在远程代码执行漏洞,该漏洞的CVS…...

卷王问卷考试系统SurveyKing,开源调查问卷和考试系统源码
卷王问卷考试系统/SurveyKing是一个功能最强大的开源调查问卷和考试系统,可以快速部署,并适用于各行业。该系统提供了在线表单设计、数据收集、统计和分析等功能,支持20多种题型,多种创建问卷方式和多种问卷设置。 无论您是需要进…...

Lombok 的 @Data 注解失效,未生成 getter/setter 方法引发的HTTP 406 错误
HTTP 状态码 406 (Not Acceptable) 和 500 (Internal Server Error) 是两类完全不同的错误,它们的含义、原因和解决方法都有显著区别。以下是详细对比: 1. HTTP 406 (Not Acceptable) 含义: 客户端请求的内容类型与服务器支持的内容类型不匹…...

树莓派超全系列教程文档--(61)树莓派摄像头高级使用方法
树莓派摄像头高级使用方法 配置通过调谐文件来调整相机行为 使用多个摄像头安装 libcam 和 rpicam-apps依赖关系开发包 文章来源: http://raspberry.dns8844.cn/documentation 原文网址 配置 大多数用例自动工作,无需更改相机配置。但是,一…...

蓝牙 BLE 扫描面试题大全(2):进阶面试题与实战演练
前文覆盖了 BLE 扫描的基础概念与经典问题蓝牙 BLE 扫描面试题大全(1):从基础到实战的深度解析-CSDN博客,但实际面试中,企业更关注候选人对复杂场景的应对能力(如多设备并发扫描、低功耗与高发现率的平衡)和前沿技术的…...

《基于Apache Flink的流处理》笔记
思维导图 1-3 章 4-7章 8-11 章 参考资料 源码: https://github.com/streaming-with-flink 博客 https://flink.apache.org/bloghttps://www.ververica.com/blog 聚会及会议 https://flink-forward.orghttps://www.meetup.com/topics/apache-flink https://n…...

前端开发面试题总结-JavaScript篇(一)
文章目录 JavaScript高频问答一、作用域与闭包1.什么是闭包(Closure)?闭包有什么应用场景和潜在问题?2.解释 JavaScript 的作用域链(Scope Chain) 二、原型与继承3.原型链是什么?如何实现继承&a…...

让AI看见世界:MCP协议与服务器的工作原理
让AI看见世界:MCP协议与服务器的工作原理 MCP(Model Context Protocol)是一种创新的通信协议,旨在让大型语言模型能够安全、高效地与外部资源进行交互。在AI技术快速发展的今天,MCP正成为连接AI与现实世界的重要桥梁。…...

Mac下Android Studio扫描根目录卡死问题记录
环境信息 操作系统: macOS 15.5 (Apple M2芯片)Android Studio版本: Meerkat Feature Drop | 2024.3.2 Patch 1 (Build #AI-243.26053.27.2432.13536105, 2025年5月22日构建) 问题现象 在项目开发过程中,提示一个依赖外部头文件的cpp源文件需要同步,点…...

使用 Streamlit 构建支持主流大模型与 Ollama 的轻量级统一平台
🎯 使用 Streamlit 构建支持主流大模型与 Ollama 的轻量级统一平台 📌 项目背景 随着大语言模型(LLM)的广泛应用,开发者常面临多个挑战: 各大模型(OpenAI、Claude、Gemini、Ollama)接口风格不统一;缺乏一个统一平台进行模型调用与测试;本地模型 Ollama 的集成与前…...

python执行测试用例,allure报乱码且未成功生成报告
allure执行测试用例时显示乱码:‘allure’ �����ڲ����ⲿ���Ҳ���ǿ�&am…...
鸿蒙DevEco Studio HarmonyOS 5跑酷小游戏实现指南
1. 项目概述 本跑酷小游戏基于鸿蒙HarmonyOS 5开发,使用DevEco Studio作为开发工具,采用Java语言实现,包含角色控制、障碍物生成和分数计算系统。 2. 项目结构 /src/main/java/com/example/runner/├── MainAbilitySlice.java // 主界…...