
Polars 提供了 utf8-lossy 编码模式,可自动替换非法 UTF-8 字节序列为 ``,无需预处理或依赖 Pandas,即可稳健读取混合/损坏编码的 CSV 流。
polars 提供了 `utf8-lossy` 编码模式,可自动替换非法 utf-8 字节序列为 ``,无需预处理或依赖 pandas,即可稳健读取混合/损坏编码的 csv 流。
在实际数据工程中,CSV 文件常因来源多样(如不同系统、区域设置或导出工具)而混杂多种字符编码(例如部分行用 cp1252,其余用 UTF-8),导致标准解析失败。虽然 pandas 支持通过 TextIOWrapper 或 encoding_errors="replace" 灵活容错,但直接将已包装的 TextIOWrapper 传给 polars.read_csv() 仍会报错——根本原因在于 Polars 的 CSV 解析器绕过 Python 的文本层,直接在 Rust 中以字节流方式解析,并不消费 TextIOWrapper 的错误处理逻辑。
幸运的是,Polars 原生支持一种专为该场景设计的编码选项:encoding='utf8-lossy'。它在底层使用 lossy_utf8 解码策略,将任何非法 UTF-8 序列(如 cp1252 字节 0x9C 在 UTF-8 上无效)静默替换为 Unicode 替换字符 ``,同时保持行列结构完整,避免解析中断。
以下为推荐实践代码:
from io import TextIOWrapper, BytesIO
import polars as pl
# 构造含混合编码的真实感测试数据(UTF-8 + cp1252)
csv_str = (
b"spam,egg\n"
+ "spam,œuf\n".encode("cp1252") # œ → 0x9C in cp1252 → invalid UTF-8
+ "spam,αυγό\n".encode("utf8") # valid UTF-8 Greek
)
content = BytesIO(csv_str)
# ✅ 正确方式:直接指定 utf8-lossy,无需 TextIOWrapper
df = pl.read_csv(content, encoding="utf8-lossy")
print(df)
输出:
shape: (2, 2) ┌──────┬──────┐ │ spam ┆ egg │ │ --- ┆ --- │ │ str ┆ str │ ╞══════╪══════╡ │ spam ┆ uf │ │ spam ┆ αυγό │ └──────┴──────┘
⚠️ 注意事项:
-
utf8-lossy仅对UTF-8 解码失败生效;若文件主体使用非 UTF 兼容编码(如纯latin1),应先转为合法 UTF-8 流,或改用encoding="latin1"(Polars 支持多种编码,但仅utf8-lossy具备容错能力); -
TextIOWrapper在 Polars 中基本无效,因其解析不经过 Python 的io.TextIOBase接口; - 若需更精细控制(如自定义替换逻辑或逐块校验),仍可先用
BytesIO+chardet检测/修复,再交由 Polars 读取,但utf8-lossy已覆盖绝大多数“脏 CSV”场景。
总结:面对编码混乱的 CSV,优先启用 pl.read_csv(..., encoding="utf8-lossy") ——简洁、高效、零依赖,是 Polars 原生健壮性的关键体现。











