如何确保Python脚本等待shutil.move完成后再执行后续操作?
嘿,这个问题我之前也碰到过——本质是跨进程的同步时机没把握好。shutil.move虽然是同步调用,但它的行为其实分两种情况,这直接导致了你遇到的问题:
如果源目录和目标目录在同一个文件系统下,
shutil.move本质是原子性的重命名操作,文件移动完成后立刻可用;但如果是跨文件系统,它会先把文件复制到目标目录,再删除源文件——这时候你的Python脚本在shutil.move返回后就写管道,但实际文件可能还在复制过程中,C程序自然找不到。
下面给你几个靠谱的解决思路:
1. 强制验证文件就绪后再写管道
不管是不是跨文件系统,都在移动完成后验证目标文件确实存在且可访问,再通知C程序。这样最稳妥:
import os import shutil import time for a_file in list_of_filenames: src = os.path.join(src_dir, a_file) dest = os.path.join(dest_dir, a_file) shutil.move(src, dest) # 第一步:确认文件存在 while not os.path.exists(dest): time.sleep(0.01) # 短间隔重试,避免占用过多资源 # 第二步:确认文件可以被读取(防止还在写缓存) file_ready = False while not file_ready: try: with open(dest, 'r'): # 尝试打开文件,验证可访问 file_ready = True except IOError: time.sleep(0.01) continue # 验证通过后再写入管道,记得flush确保内容立刻发送 pipe.write(f"{a_file}\n") pipe.flush()
2. 区分文件系统优化逻辑
如果大部分场景是同文件系统移动,可以先判断源和目标是否在同一个FS,只在跨FS时做验证,提升效率:
def is_same_filesystem(dir1, dir2): # 通过设备ID判断是否同文件系统 return os.stat(dir1).st_dev == os.stat(dir2).st_dev for a_file in list_of_filenames: src = os.path.join(src_dir, a_file) dest = os.path.join(dest_dir, a_file) shutil.move(src, dest) # 只有跨文件系统时才做验证 if not is_same_filesystem(src_dir, dest_dir): while not os.path.exists(dest): time.sleep(0.01) try: with open(dest, 'r'): pass except IOError: time.sleep(0.01) continue pipe.write(f"{a_file}\n") pipe.flush()
3. 让C程序配合做双向同步
如果有权限修改C程序的话,最好的方式是做双向确认:Python发送文件名后,等待C程序返回“文件已就绪”的信号,再继续处理下一个文件。比如:
- Python端代码片段:
import select for a_file in list_of_filenames: # 移动文件+验证逻辑... pipe.write(f"{a_file}\n") pipe.flush() # 等待C程序的确认信号,超时5秒做异常处理 ready, _, _ = select.select([pipe], [], [], 5.0) if ready: ack = pipe.readline().strip() if ack != "FILE_READY": # 处理异常:比如重试移动或记录日志 print(f"Warning: C program failed to confirm {a_file}") else: print(f"Timeout waiting for C program ack for {a_file}")
- C程序端读取文件名后,检查文件存在且可访问,再向管道写入
FILE_READY\n确认。
这样可以从根本上避免同步问题,适合对可靠性要求高的场景。
内容的提问来源于stack exchange,提问作者Valentin B.
相关产品推荐
相关产品推荐

