Python for循环处理抛异常迭代器:记录异常后继续迭代的方法
问题核心说明
你遇到的UnicodeDecodeError并非csv.reader迭代逻辑抛出,而是底层标准输入流在做字节到文本解码时触发。如果直接在遍历reader的循环里加异常捕获,无法实现「记录异常后继续迭代」的效果:解码异常抛出时,默认文本流的迭代器已经进入无效状态,后续继续迭代会出现数据错乱、丢内容甚至再次抛错的问题。
Pythonic 实现方案
核心思路是接管流的解码逻辑,不要依赖默认的严格解码模式,从根源上避免解码异常打断整个迭代流程,根据需求可以选两种实现:
方案1:自定义解码错误处理(推荐,不丢失行内容)
通过标准库codecs模块注册自定义的解码错误回调,遇到坏字节时自动记录日志,用Unicode替换字符填充坏位置后继续解码,完全不打断csv的正常解析流程:
import csv import sys import logging import codecs logging.basicConfig(level=logging.WARNING) csv.field_size_limit(10_000_000) # 解码异常回调:记录日志后返回替换字符,指定后续解码位置 def decode_error_handler(exc: UnicodeDecodeError): logging.warning( f"解码异常,字节位置{exc.start}-{exc.end},原因:{exc.reason},坏字节将替换为\ufffd" ) return ("\ufffd", exc.end) # 注册自定义错误处理规则 codecs.register_error("log_and_replace", decode_error_handler) # 从二进制缓冲区重新包装带容错能力的文本流 stdin_wrapper = codecs.getreader("utf-8")(sys.stdin.buffer, errors="log_and_replace") reader = csv.reader(stdin_wrapper) for row in reader: # 正常业务处理逻辑 pass
这个方案完全复用标准库csv的解析能力,不需要自己处理行拆分、引号嵌套等边界情况,坏行的其余正常内容可以保留,后续只要检查行内是否存在\ufffd字符就能定位损坏的行。
方案2:逐行二进制读取(适合整行跳过场景)
如果你不需要保留损坏行的内容,只要遇到解码错误就跳过整行,可以直接从二进制缓冲区逐行读取,单独给每一行做解码:
import csv import sys import logging logging.basicConfig(level=logging.WARNING) csv.field_size_limit(10_000_000) for line_no, raw_line in enumerate(sys.stdin.buffer, start=1): try: text_line = raw_line.decode("utf-8") except UnicodeDecodeError as e: logging.warning(f"第{line_no}行解码失败,已跳过,原因:{e.reason}") continue # 解码成功的行交给csv解析 for row in csv.reader([text_line]): # 正常业务处理逻辑 pass
这个方案逻辑更直观,但如果csv内容里存在带换行符的引号包裹字段,逐二进制行拆分可能破坏字段结构,兼容性弱于第一种方案。
避坑提示
不要直接在原遍历循环外层套try-except后强行继续迭代,默认文本流抛出解码异常后,内部读指针的状态不可控,继续读取会出现内容错乱、数据丢失的问题。
内容的提问来源于stack exchange,提问作者static_rtti
相关产品推荐
相关产品推荐

