为何except代码块无法捕获FileExistsError异常?
看起来你遇到的是Windows系统下os.rename()的特定行为问题——在Windows上,当目标文件已经存在时,os.rename()会直接抛出FileExistsError,但有时候单纯捕获这个异常类可能因为环境或Python版本的细节没生效?或者我们可以换更稳妥的处理方式。
问题根源
Windows和Unix-like系统对os.rename()的行为差异很大:Unix下会直接覆盖已存在的目标文件,而Windows则严格禁止,直接抛出错误。你的代码逻辑本身没问题,但可能在某些场景下(比如权限冲突、或者Python版本对异常类的处理细节),单纯捕获FileExistsError没覆盖到所有情况。
几种可行的解决方案
1. 先检查目标文件是否存在,再执行重命名
这是最直观的方式,先判断目标文件是否存在,存在就直接跳过,避免触发异常:
import os # 你的purge_DBP_files函数示例 def purge_DBP_files(new_folder): # 假设这里有遍历文件的逻辑,生成infilename和newname for filename in os.listdir(new_folder): if filename.endswith(".DBP"): infilename = os.path.join(new_folder, filename) newname = os.path.join(new_folder, os.path.splitext(filename)[0] + ".part") if os.path.exists(newname): print(f'{newname} already exists, skipping') continue try: os.rename(infilename, newname) except Exception as e: print(f'Failed to rename {infilename}: {str(e)}')
⚠️ 注意:这种方式存在极小的竞态条件——如果在你检查文件是否存在之后,到执行重命名之前,其他进程创建了目标文件,还是会触发异常,所以外层的try-except还是有必要保留。
2. 捕获OSError并判断错误编号
因为FileExistsError是OSError的子类,在Windows下对应的错误编号是errno.EEXIST(对应WinError 183),我们可以直接捕获OSError并判断错误类型,这样兼容性更好:
import os import errno try: os.rename(infilename, newname) except OSError as e: if e.errno == errno.EEXIST: print(f'{newname} already exists') else: # 如果是其他错误(比如权限不足、源文件不存在),重新抛出异常 raise
这种方式能确保精准捕获到“目标文件已存在”的错误,同时不会忽略其他异常情况。
为什么你的原代码可能没生效?
如果你的代码缩进没问题,那大概率是环境相关的小细节:比如某些Python版本在Windows下,FileExistsError的抛出逻辑有细微差异,或者你的脚本运行时存在权限问题(比如目标文件被其他进程锁定),导致抛出的异常虽然是WinError 183,但没有被FileExistsError正确捕获。用第二种方案就能解决这个问题。
内容的提问来源于stack exchange,提问作者Chris Macaluso

