Python使用glob遍历路径时os.path.exists部分返回False问题求助
问题诱因
- 网络共享盘(SMB/CIFS协议)的目录枚举和文件存在性检查是两个独立请求,SMB客户端默认会缓存30秒左右的目录列表,
glob.glob调用时拿到的是缓存的旧目录条目,后续调用os.path.exists时走实时请求,此时如果对应文件已经被移动、删除,就会返回False。 - 手动拼接路径的方式存在格式隐患:如果
<dir-path>末尾本身包含反斜杠,拼接后会出现双反斜杠,部分SMB服务器对这类路径格式兼容性差,会判定路径无效。 - 路径存在特殊情况:比如路径长度超过Windows默认260字符限制、文件名包含SMB服务器不兼容的Unicode特殊字符、文件被其他进程独占锁定,部分SMB服务器会对被独占锁定的文件拒绝存在性检查请求,返回不存在。
- 快捷方式/软链接指向失效:如果枚举到的是快捷方式(.lnk)或目录软链接,
glob可以正常枚举到该对象本身,但如果配置了文件系统自动解析链接,os.path.exists会检查指向的目标是否存在,目标失效就会返回False。
排查方案
- 首先打印所有返回
False的路径字符串,确认是否存在双反斜杠、特殊字符、超长路径的问题。 - 替换
glob.glob为os.listdir/os.scandir做相同逻辑的测试,排除glob本身的实现问题。 - 对返回
False的路径调用os.stat,查看抛出的异常类型,区分是真的不存在、权限拒绝还是路径格式错误。 - 缓存
glob的结果后间隔10秒再重新执行存在性检查,如果结果发生变化,可确认是SMB目录缓存导致的不一致。
解决建议
- 改用标准路径拼接方式:使用
os.path.join或者pathlib处理路径,避免手动拼接反斜杠的格式问题,示例:# 旧写法 for f in glob.glob(<dir-path>+"\\*"): # 新写法 for f in glob.glob(os.path.join(<dir-path>, "*")): # 更推荐Python3.4+的pathlib写法,无需额外做存在性检查 from pathlib import Path for f in Path(<dir-path>).iterdir(): - 替换存在性检查方式:使用
os.scandir遍历目录,返回的DirEntry对象自带缓存的属性,不需要额外调用os.path.exists,在网络共享盘下性能和准确率都更高:for entry in os.scandir(<dir-path>): print(entry.name, entry.exists()) - 处理长路径问题:Windows下可以给路径添加
\\?\前缀绕过260字符限制,示例:glob.glob(f"\\\\?\\{os.path.abspath(<dir-path>)}\\*") - 临时禁用SMB客户端目录缓存,或者在枚举目录前先执行一次目录刷新操作,避免拿到过期的缓存条目。
内容的提问来源于stack exchange,提问作者Nir Sela
相关产品推荐
相关产品推荐

