Python中Polars read_csv读取空CSV异常未捕获问题求解
问题根因
你之前的异常捕获逻辑单独运行正常,结合FuncAnimation失效核心是三个原因:
FuncAnimation的帧更新回调默认跑在GUI后端的事件循环线程里,如果你只给pl.read_csv加了异常捕获,没有覆盖整个更新回调流程,线程内逃逸的异常会直接终止程序,不会走到你写的except分支。- 文件被其他程序重置重开的瞬间,除了空CSV触发的
pl.exceptions.NoDataError,还可能碰到文件占用的PermissionError、写入截断触发的pl.exceptions.ComputeError,只捕获单一异常类会漏判。 - Polars 0.13.24~0.14.0区间版本存在已知bug:多线程场景下读空文件的异常会被包装成通用Runtime异常,精准捕获
NoDataError无法命中。
可直接复用的解决方案
按以下顺序调整代码即可解决问题,不需要改现有业务逻辑:
- 第一步:给CSV读取加前置校验,从源头规避空文件读取场景
每次读取前先判断文件存在性和文件大小,空文件直接返回带预设列名的空Polars DataFrame,不要直接触发pl.read_csv,参考实现:import os import polars as pl # 替换成你实际的预设列和对应字段类型 PRESET_SCHEMA = { "timestamp": pl.Float64, "value": pl.Float64 } CSV_FILE_PATH = "realtime_data.csv" def load_csv_data(): # 前置校验:文件不存在/大小不足10字节直接返回空表(小于10字节大概率是刚重置的空文件、连表头都没写完) if not os.path.exists(CSV_FILE_PATH) or os.path.getsize(CSV_FILE_PATH) < 10: return pl.DataFrame(schema=PRESET_SCHEMA) # 全量捕获读文件阶段的所有可能异常 try: df = pl.read_csv(CSV_FILE_PATH, dtypes=PRESET_SCHEMA) # 这里放你原有的数据转换逻辑 return df except (pl.exceptions.NoDataError, pl.exceptions.ComputeError, OSError, PermissionError): return pl.DataFrame(schema=PRESET_SCHEMA) - 第二步:给
FuncAnimation的更新回调加全量异常兜底
把整个帧更新逻辑包裹在try-except块中,同时初始化动画时关闭帧缓存,避免异常逃逸到GUI事件循环,参考实现:import matplotlib.pyplot as plt from matplotlib.animation import FuncAnimation fig, ax = plt.subplots() # 初始化你的绘图元素,比如折线、散点 plot_line, = ax.plot([], [], label="realtime_value") ax.legend() def render_frame(frame): try: df = load_csv_data() if df.is_empty(): # 空数据时保留上一帧渲染结果即可,不需要清空 return plot_line, # 这里放你原有的绘图更新逻辑 # plot_line.set_data(df["timestamp"], df["value"]) # ax.relim() # ax.autoscale_view() return plot_line, except Exception as e: # 捕获所有未预期异常,打印日志后跳过当前帧,不终止程序 print(f"跳过当前帧,渲染异常: {repr(e)}") return plot_line, # 注意必须加cache_frame_data=False,关闭matplotlib的帧缓存避免异常透传 ani = FuncAnimation( fig=fig, func=render_frame, interval=500, # 匹配你500ms的刷新间隔 blit=True, # 开blit加速也不会漏异常 cache_frame_data=False ) plt.show() - 第三步:可选升级Polars版本
如果执行完前两步还是有异常漏出,直接把Polars升级到0.14.1及以上版本即可,修复了早期版本异常包装导致的捕获失效问题。
避坑提示
不要尝试把整个plt.show()包裹在try-except里,GUI事件循环内的异常不会被主线程的外层捕获,必须在帧更新回调内部做异常兜底。
内容的提问来源于stack exchange,提问作者Campbell He
相关产品推荐
相关产品推荐

