如何暂停ThreadPool执行指定函数后恢复,解决文件夹监控读文件权限报错问题
问题根因
你遇到的[Errno 13] Permission denied报错并非由监控线程占用文件夹导致,核心原因有三点:
- 文件新增的通知触发时,将文件写入文件夹的程序还未完成写入操作、未释放文件锁,此时直接读取文件就会触发权限不足报错
- 现有逻辑存在重复执行问题:你同时用
thread_pool_executor.submit(self.process_csv)异步提交任务,又同步调用self.process_csv(),两个线程同时读取同一个文件也会触发锁冲突 - 读取文件时使用了
r+读写模式,该模式比只读的r模式要求更高的操作权限,也会提升权限报错概率 process_csv方法中硬编码了测试文件名,没有使用实际新增的文件路径,属于潜在逻辑缺陷
修复方案
方案1:等待文件锁释放(优先推荐,无需暂停监控)
不需要暂停监控线程,仅需增加文件可用性校验逻辑,等待文件锁释放后再读取即可,改动最小:
- 新增文件可用性校验工具方法:
def is_file_available(self, file_path, retry_count=5, wait_interval=1): # 重试5次,每次间隔1秒,判断文件是否可读 for _ in range(retry_count): try: with open(file_path, 'r') as f: return True except PermissionError: time.sleep(wait_interval) return False
- 修改
process_csv方法,接收动态传入的文件路径,先校验可用性再读取:
# 方法新增data_file参数,去掉硬编码的文件名 def process_csv(self, data_file): data_file_delimiter = ',' largest_column_count = 0 # 先判断文件是否可用 if not self.is_file_available(data_file): print(f"文件{data_file}暂时无法访问,跳过处理") return # 把原代码的r+改为r只读模式 with open(data_file, 'r') as temp_f: lines = temp_f.readlines() for l in lines: column_count = len(l.split(data_file_delimiter)) + 1 largest_column_count = column_count if largest_column_count < column_count else largest_column_count column_names = [i for i in range(0, largest_column_count)] df = pd.read_csv(data_file, delimiter=data_file_delimiter, names=column_names) df.fillna("", inplace=True) print(df)
- 修正文件处理位置的冗余逻辑,去掉重复调用:
if fType == ".csv" or fType == ".txt": data_file = a_string # 删掉原有的submit异步提交和重复的同步调用,二选一即可 # 同步执行写法: self.process_csv(data_file) # 异步提交写法:thread_pool_executor.submit(self.process_csv, data_file)
方案2:暂停监控线程处理完成后恢复(符合你最初的需求)
如果确实需要暂停监控避免重复触发,可以通过标志位控制监控线程的运行状态:
- 在
__init__方法中新增暂停标志位:
def __init__(self, parent, title): super(MainFrame, self).__init__(parent, title=title,size=(600,400)) self.monitor_paused = False # 新增监控暂停标志位 # 原有初始化逻辑不变
- 修改
monitor_folder方法的循环逻辑,增加暂停判断:
while 1: # 新增暂停判断,暂停时跳过监听逻辑 if self.monitor_paused: time.sleep(0.5) continue result = win32event.WaitForSingleObject (change_handle, 500) # 原有监听逻辑不变
- 文件处理位置增加暂停/恢复控制:
if fType == ".csv" or fType == ".txt": data_file = a_string self.monitor_paused = True # 暂停监控 self.process_csv(data_file) # 同步处理文件 self.monitor_paused = False # 处理完成恢复监控
附加优化建议
获取文件后缀不要用字符串切片,改用os.path.splitext(a_string)[1].lower(),可以避免文件名长度不足4位、后缀大写等异常情况,示例:
fType = os.path.splitext(a_string)[1].lower() if fType == ".csv" or fType == ".txt": # 处理逻辑
内容的提问来源于stack exchange,提问作者cmccall95
相关产品推荐
相关产品推荐

