DBR15.2/Python3.11下日志文件读取报FileNotFoundError求助
问题诊断与解决方案
核心现象分析
从DBR 10.4(Python3.8)迁移到DBR15.2(Python3.11)后出现的文件访问异常,核心原因集中在文件系统视图不一致、Python版本的命令语法兼容性以及日志文件生命周期的同步问题:
- Python的
os.listdir()与shell的ls命令存在目录视图差异,是因为新版本DBR的分布式文件系统(如DBFS)缓存策略变更,导致Python模块无法实时获取目录更新 os.popen("logpath/logfile")在Python3.11报错,是因为该写法本身不是合法shell命令,3.8版本未严格校验但无有效输出,3.11则直接抛出语法错误- 首次上传正常、二次上传失败,大概率是日志文件的句柄未正确刷新/关闭,或日志滚动导致原文件路径失效
针对性解决方案
1. 修复os.popen的命令语法错误
直接传入文件路径给os.popen是无效的,需使用合法shell命令读取文件,或更推荐用Python原生文件操作替代shell调用:
# 错误写法 # os.popen("logpath/logfile") # 正确shell调用写法 with os.popen(f"cat {logpath}/{logfile}") as f: content = f.read() # 更安全的Python原生读取(优先推荐) with open(f"{logpath}/{logfile}", "r", encoding="utf-8") as f: content = f.read()
2. 解决目录视图不一致问题
用os.scandir()替代os.listdir(),该方法会实时读取目录元数据,避免缓存导致的视图延迟:
# 替代os.listdir的遍历逻辑 for entry in os.scandir("logpath"): if entry.is_file(): log_file_name = entry.name # 执行后续上传逻辑
若必须使用os.listdir(),可在调用前触发文件系统同步:
os.system("sync") files = os.listdir("logpath")
3. 确保日志文件的正确同步
在上传日志前,强制刷新日志处理器的缓存并关闭文件句柄,避免文件系统无法识别已写入的内容:
import logging def prepare_log_for_upload(logger): for handler in logger.handlers: if isinstance(handler, logging.FileHandler): handler.flush() # 强制写入缓存内容到磁盘 handler.close() # 临时关闭文件句柄,确保文件状态同步 # 上传完成后可重新添加handler恢复日志写入
4. 处理日志滚动导致的文件路径失效
如果使用了TimedRotatingFileHandler或RotatingFileHandler,二次调用时原日志文件可能已被重命名/删除。需调整上传逻辑:
- 上传时优先读取当前活跃的日志文件(而非历史文件名)
- 在日志滚动触发后,立即更新上传的目标文件路径
5. 添加文件存在性重试逻辑
针对分布式文件系统的同步延迟,增加重试机制确保文件可被访问:
import time def upload_log_with_retry(log_file_path, max_retries=3, delay=1): for _ in range(max_retries): if os.path.exists(log_file_path) and os.path.isfile(log_file_path): # 执行Blob上传逻辑 return time.sleep(delay) raise FileNotFoundError(f"Failed to access file {log_file_path} after {max_retries} retries")
6. 验证路径一致性
在Databricks环境中,使用绝对路径而非相对路径,避免路径解析差异:
# 替换相对路径为绝对DBFS路径 log_path = "/dbfs/mnt/your-log-mount-path/" files = os.listdir(log_path)
内容的提问来源于stack exchange,提问作者ArniBandyo
相关产品推荐
相关产品推荐

