Python CSV模块处理子进程STDOUT流时非字符串迭代器报错解决
问题:使用csv模块读取subprocess返回的ffprobe CSV字节流报错
调用subprocess.run()执行ffprobe获取视频流的CSV格式结果,尝试用csv.reader解析时出现报错,以下是详细场景及解决方案:
原代码
import os import subprocess import csv for file in os.listdir("/Temp/Video"): if file.endswith(".mkv"): print(os.path.join("/Temp/Video", file)) ps = subprocess.run(["ffprobe", "-show_streams", "-print_format", "csv", "-i", "/Temp/Video/" + file], capture_output = True) print(ps.stdout) reader = csv.reader(ps.stdout) results = [] for row in reader: results.append(row)
报错信息
Traceback (most recent call last): File "C:\Users\mbmas\eclipse-workspace\DolbyAtmosToFlac\com\mbm\main.py", line 12, in <module> for row in reader: _csv.Error: iterator should return strings, not int (the file should be opened in text mode)
问题原因
subprocess.run()默认返回的stdout是字节流(bytes类型),而csv.reader要求输入是文本模式的可迭代对象(即字符串序列)。直接传入bytes时,迭代会返回单个字节对应的整数,因此触发报错。
解决方案
方法1:让subprocess直接返回文本字符串
给subprocess.run()添加text=True参数(Python 3.7+支持,等价于旧版的universal_newlines=True),这样stdout会自动解码为字符串:
import os import subprocess import csv for file in os.listdir("/Temp/Video"): if file.endswith(".mkv"): file_path = os.path.join("/Temp/Video", file) print(file_path) # 添加text=True,让stdout返回字符串 ps = subprocess.run( ["ffprobe", "-show_streams", "-print_format", "csv", "-i", file_path], capture_output=True, text=True ) reader = csv.reader(ps.stdout.splitlines()) # 按行分割成可迭代对象 results = list(reader) print(results)
方法2:手动解码字节流并包装为类文件对象
如果需要处理字节流,先将其解码为字符串,再用io.StringIO包装成类文件对象,传给csv.reader:
import os import subprocess import csv import io for file in os.listdir("/Temp/Video"): if file.endswith(".mkv"): file_path = os.path.join("/Temp/Video", file) print(file_path) ps = subprocess.run( ["ffprobe", "-show_streams", "-print_format", "csv", "-i", file_path], capture_output=True ) # 解码字节流为字符串,并用StringIO包装 csv_text = ps.stdout.decode('utf-8') reader = csv.reader(io.StringIO(csv_text)) results = list(reader) print(results)
注意:两种方法都需要确保ffprobe输出的编码是UTF-8(大部分场景下默认是),如果有编码问题,可以指定
encoding参数(方法1中给subprocess.run()加encoding='utf-8',方法2中decode()里指定对应编码)。
内容的提问来源于stack exchange,提问作者mbmast
相关产品推荐
相关产品推荐

