<think>我们将修改代码以实现以下需求:
1. 监控整个目录树(包括子目录)中的新文件夹出现(不仅仅是第一级子目录)。
2. 当任何目录(包括多级子目录)中出现新文件夹时,读取该新文件夹的路径(注意:我们只关心文件夹,不关心文件)。
3. 修改目标脚本(TEST.py)中的target_path变量为这个新文件夹的路径。
4. 运行修改后的目标脚本。
由于原代码只监控一级目录,我们需要递归监控整个目录树。我们可以使用watchdog库来实时监控文件系统事件,但原代码使用的是轮询方式。为了满足需求,我们将改为使用watchdog来监控整个目录树。
但是,考虑到需求中要求监控整个目录树,并且任何子文件夹出现新文件夹(即目录创建事件)都要处理,我们可以这样设计:
- 使用watchdog的FileSystemEventHandler来监听目录创建事件(包括多级目录)。
- 注意:我们只关心新创建的目录(即文件夹),并且一旦创建就立即处理。
然而,需求中要求的是“任何子文件或者二级子文件夹发生变化(有新的文件夹出现)”,这里我们理解为:在监控的目录树中,任何地方出现新的文件夹(无论多少级)都要处理。
但是,为了避免重复处理,我们只处理新创建的文件夹(即事件中的目录创建),并且只处理那些我们感兴趣的路径?实际上,需求并没有限制路径,所以任何新文件夹都要处理。
但是,注意:我们只关心新文件夹本身,而不是文件夹内的变化。所以,我们监听的是目录创建事件(on_created事件,且是目录)。
步骤:
1. 配置监控的根目录(WATCH_FOLDER)为"D:\Users\x00708\Nano"。
2. 使用watchdog递归监控整个目录树。
3. 当检测到目录创建事件时,获取该新目录的路径。
4. 修改TEST.py中的target_path为该新目录路径。
5. 运行TEST.py。
注意:由于新创建的文件夹可能是多级嵌套中的任何一级,所以我们需要处理所有目录创建事件。但是,要小心事件触发时文件夹可能还未完全同步(比如,正在复制文件到该文件夹)。因此,我们可以考虑在检测到事件后等待一段时间(如2分钟)再处理,以确保文件夹内数据同步完成。
但是,需求没有说明新文件夹是如何产生的。如果是一次性创建整个目录树,那么可能会触发多个事件(先创建父目录,再创建子目录)。为了避免重复处理,我们可以设置一个去重机制,或者只处理最底层的目录?实际上,需求中要求的是“新出现的文件夹”,我们可能希望处理每一个新出现的文件夹。然而,这可能会导致多次处理同一个项目(比如,先创建了父目录,然后创建子目录,然后又在子目录下创建子目录)。所以,我们需要明确:我们只处理新出现的文件夹,不管它是不是嵌套的。
根据需求,我们只需要将target_path设置为新出现的文件夹路径,并运行脚本。所以,每个新文件夹都会触发一次脚本运行。
但是,这可能会产生大量的脚本运行,因为任何嵌套的新文件夹都会触发。我们需要确认需求:是否只关心特定层级或特定模式?需求中并没有说明,所以我们将处理所有新文件夹。
然而,考虑到性能,我们可能需要过滤掉一些临时文件夹?但需求没有提供过滤条件,因此我们暂时不做过滤。
实现方案:
我们将使用watchdog来监控整个目录树。当有目录创建事件时,我们记录该目录的路径,然后启动一个定时器(例如,等待2分钟)后处理,这样可以让文件夹内的文件同步完成。
由于可能同时有多个事件,我们需要一个事件队列,并且每个事件等待2分钟后执行。但注意,如果同一个文件夹在2分钟内被多次创建(实际上不可能),我们需要去重。
我们可以使用一个队列和定时器,但为了简单,我们可以使用线程池,每个事件触发后,启动一个线程等待2分钟,然后执行修改和运行脚本。
代码结构:
- 导入watchdog相关模块。
- 自定义事件处理器,继承FileSystemEventHandler,重写on_created方法。
- 在on_created中,如果是目录,则启动一个线程,线程中等待2分钟,然后调用修改和运行脚本的函数。
但是,为了避免同时处理过多的事件,我们可以使用线程池来控制并发。
考虑到需求,我们假设新文件夹的出现频率不会太高,所以我们可以为每个事件启动一个线程。
具体步骤:
1. 安装watchdog:`pip install watchdog`
2. 编写代码。
我们将修改代码,使用watchdog来监控整个目录树。
注意:由于原代码中已经有一个轮询结构,我们将完全重构main函数,使用watchdog的Observer。
另外,为了避免在文件夹同步过程中处理,我们等待2分钟(120秒)后再执行。
同时,为了避免同一个文件夹被多次处理(由于事件可能会触发多次?),我们可以记录最近处理过的文件夹,并在一段时间内忽略重复的。但为了简单,我们暂时不做,因为同一个文件夹的创建事件通常只发生一次。
我们定义以下函数:
- modify_and_run_script(target_path): 修改TEST.py中的target_path为target_path,然后运行它。
修改TEST.py的方法:我们使用正则表达式替换,因为target_path的赋值语句可能在不同行,格式可能不同(有单引号、双引号、raw字符串等)。我们假设TEST.py中有一行类似:
target_path = "原来的路径"
我们将替换为:
target_path = r"新的路径" (使用原始字符串,避免转义问题)
如果TEST.py中没有target_path变量,我们将报错。
代码实现如下:
</think>
我将基于您提供的代码进行修改,实现递归监控整个目录树并在任何子目录出现新文件夹时执行指定操作的功能。以下是完整的解决方案:
```python
import os
import time
import subprocess
import re
import warnings
from watchdog.observers import Observer
from watchdog.events import FileSystemEventHandler
warnings.simplefilter("ignore") # 忽略所有警告
# 配置参数
WATCH_ROOT = r"D:\Users\x00708\Nano" # 监控的根目录
TEST_SCRIPT = r"D:\Users\x00708\Nano\TEST.py" # 要修改和执行的脚本
PYTHON_EXE = r"D:\Users\x00708\SRAM_Classification_CDF\.venv\Scripts\python.exe" # Python解释器路径
# 存储已处理文件夹的状态
processed_folders = set()
class FolderChangeHandler(FileSystemEventHandler):
def __init__(self):
super().__init__()
# 初始化时扫描所有现有文件夹
self.scan_existing_folders()
def scan_existing_folders(self):
"""初始化时扫描并记录所有现有文件夹"""
for root, dirs, files in os.walk(WATCH_ROOT):
for dir_name in dirs:
full_path = os.path.join(root, dir_name)
processed_folders.add(full_path)
print(f"初始化完成,已记录 {len(processed_folders)} 个文件夹")
def on_created(self, event):
"""处理文件夹创建事件"""
if not event.is_directory:
return
new_folder = event.src_path
if new_folder not in processed_folders:
print(f"检测到新文件夹: {new_folder}")
# 等待文件夹内容稳定(避免处理空文件夹)
time.sleep(5)
# 处理新文件夹
process_new_folder(new_folder)
# 添加到已处理列表
processed_folders.add(new_folder)
def modify_and_run_script(target_path):
"""修改TEST.py中的target_path并执行"""
try:
# 读取原始脚本内容
try:
with open(TEST_SCRIPT, 'r', encoding='utf-8') as f:
content = f.read()
except UnicodeDecodeError:
with open(TEST_SCRIPT, 'r', encoding='gbk') as f:
content = f.read()
# 替换target_path - 使用正则表达式匹配不同格式
new_content = re.sub(
r'(target_path\s*=\s*[ur]?[\'"]).*?([\'"])',
rf'\g<1>{target_path}\g<2>',
content
)
# 创建临时脚本路径
temp_script = os.path.join(os.path.dirname(TEST_SCRIPT), "TEMP_" + os.path.basename(TEST_SCRIPT))
# 写入临时脚本
with open(temp_script, 'w', encoding='utf-8') as f:
f.write(new_content)
print(f"正在处理路径: {target_path}")
# 执行临时脚本
result = subprocess.run(
[PYTHON_EXE, temp_script],
capture_output=True,
text=True,
check=True
)
print(f"脚本执行成功:\n{result.stdout}")
if result.stderr:
print(f"警告信息:\n{result.stderr}")
# 删除临时脚本
os.remove(temp_script)
return True
except subprocess.CalledProcessError as e:
print(f"脚本执行失败:\n{e.stderr}")
return False
except Exception as e:
print(f"处理脚本时出错: {e}")
return False
def process_new_folder(folder_path):
"""处理新检测到的文件夹"""
print(f"开始处理文件夹: {folder_path}")
# 检查文件夹是否有效
if not os.path.isdir(folder_path):
print(f"警告: '{folder_path}' 不是有效文件夹")
return False
# 修改并运行脚本
return modify_and_run_script(folder_path)
def main():
# 确保监控目录存在
if not os.path.exists(WATCH_ROOT):
os.makedirs(WATCH_ROOT)
print(f"创建了监控目录: {WATCH_ROOT}")
# 初始化事件处理器
event_handler = FolderChangeHandler()
# 创建观察者
observer = Observer()
observer.schedule(event_handler, WATCH_ROOT, recursive=True)
print(f"开始监控目录树: {WATCH_ROOT}")
print(f"监控规则: 递归监控所有子目录")
print(f"检测到新文件夹时将修改并执行: {TEST_SCRIPT}")
print("按 Ctrl+C 停止监控...")
observer.start()
try:
while True:
time.sleep(1)
except KeyboardInterrupt:
observer.stop()
observer.join()
print("监控已停止")
if __name__ == "__main__":
main()
```
### 代码详细解释:
1. **核心功能**:
- 使用 `watchdog` 库递归监控整个目录树
- 检测任何位置的新文件夹创建事件
- 自动修改目标脚本中的路径变量
- 执行修改后的脚本处理新文件夹
2. **监控机制**:
- `FolderChangeHandler` 类继承自 `FileSystemEventHandler`
- 重写 `on_created` 方法处理文件夹创建事件
- 使用 `Observer` 对象递归监控整个目录树 (`recursive=True`)
3. **状态管理**:
- `processed_folders` 集合记录已处理的文件夹路径
- `scan_existing_folders` 方法初始化时扫描所有现有文件夹
- 新文件夹检测后立即添加到已处理集合
4. **脚本处理流程**:
- `modify_and_run_script` 函数:
- 使用正则表达式替换路径变量
- 创建临时脚本避免修改原始文件
- 执行脚本并捕获输出结果
- 清理临时文件
- `process_new_folder` 函数作为事件处理入口
5. **健壮性设计**:
- 处理文件编码问题(UTF-8 和 GBK)
- 等待5秒确保文件夹内容稳定
- 优雅处理键盘中断(Ctrl+C)
- 自动创建监控目录(如果不存在)
- 详细的执行日志输出
### 使用说明:
1. **安装依赖**:
```bash
pip install watchdog
```
2. **TEST.py 要求**:
- 必须包含 `target_path` 变量
- 示例格式:
```python
# TEST.py
target_path = "默认路径" # 将被自动替换
def main():
print(f"处理路径: {target_path}")
# 您的处理逻辑...
if __name__ == "__main__":
main()
```
3. **配置参数**:
- `WATCH_ROOT`: 监控的根目录(递归所有子目录)
- `TEST_SCRIPT`: 要修改和执行的Python脚本
- `PYTHON_EXE`: Python解释器路径
4. **运行程序**:
```bash
python folder_monitor.py
```
5. **测试方法**:
- 在监控目录树中的任何位置创建新文件夹
- 程序将自动检测并执行处理
- 示例:
```
检测到新文件夹: D:\Users\x00708\Nano\2026\3_7_test
正在处理路径: D:\Users\x00708\Nano\2026\3_7_test
脚本执行成功: ...
```
### 注意事项:
1. **递归监控**:
- 程序会监控指定根目录下的所有子目录
- 包括任何深度的嵌套目录
2. **性能考虑**:
- 监控大型目录树可能消耗较多资源
- 对于特别庞大的目录,可能需要优化
3. **文件夹稳定性**:
- 检测到新文件夹后等待5秒再处理
- 确保文件夹内容已完全写入
4. **临时文件**:
- 程序会创建临时脚本 `TEMP_TEST.py`
- 确保有足够的磁盘空间和写入权限