Python CSV模块解析返回单个字符而非字符串的问题排查
问题:csv.reader解析ffprobe CSV输出时返回单个字符列表
调用ffprobe获取CSV格式的视频流信息,打印输出符合CSV格式,但用csv.reader解析subprocess.run()返回的stdout字符串时,得到的却是单个字符组成的列表,而非预期的逗号分隔字段列表。
原代码
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, text = True) print("------------------------------------------") print(ps.stdout) print("------------------------------------------") reader = csv.reader(ps.stdout) for row in reader: print(row) exit(0)
输出情况
实际stdout输出
stream,0,h264,H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10,High,video,[0][0][0][0],0x0000,1920,1080,1920,1080,0,0,2,1:1,16:9,yuv420p,40,unknown,unknown,unknown,unknown,left,progressive,1,true,4,N/A,24000/1001,24000/1001,1/1000,0,0.000000,N/A,N/A,N/A,N/A,8,N/A,N/A,N/A,46,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,eng,17936509,01:20:18.271791666,115523,10802870592,001011,MakeMKV v1.16.4 win(x64-release),2021-08-20 19:09:26,BPS DURATION NUMBER_OF_FRAMES NUMBER_OF_BYTES SOURCE_ID,Lavc59.7.102 libx264,00:01:30.010000000 stream,1,vorbis,Vorbis,unknown,audio,[0][0][0][0],0x0000,fltp,48000,3,3.0,0,0,N/A,0/0,0/0,1/1000,0,0.000000,N/A,N/A,N/A,N/A,N/A,N/A,N/A,N/A,3314,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,eng,Surround 3.0,2422660,01:20:18.272000000,451713,1459129736,001100,MakeMKV v1.16.4 win(x64-release),2021-08-20 19:09:26,BPS DURATION NUMBER_OF_FRAMES NUMBER_OF_BYTES SOURCE_ID,Lavc59.7.102 libvorbis,00:01:30.003000000
异常解析结果
['s'] ['t'] ['r'] ['e'] ['a'] ['m'] ['', ''] ['0'] ['', ''] ['h'] ['2'] ['6'] ['4'] ...
预期结果
['stream', '0', 'h264', 'H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10', ...] ['stream', '1', 'vorbis', 'Vorbis', 'unknown', 'audio', ...]
原因
csv.reader()要求参数是按行迭代的对象(比如文件对象、每行字符串组成的列表)。直接传入ps.stdout字符串时,Python会把字符串当作字符序列迭代——每个字符被视为一行,csv.reader解析这单个字符的"行",自然返回只有单个字符的列表。
解决方案
有两种常见修复方式:
方式1:用splitlines()分割字符串为行列表
将ps.stdout拆分成每行字符串的列表,再传给csv.reader:
reader = csv.reader(ps.stdout.splitlines())
方式2:用io.StringIO包装为类文件对象
把字符串转换成类似文件的可迭代对象,更贴合csv.reader的设计场景:
import io reader = csv.reader(io.StringIO(ps.stdout))
修改后的完整代码
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, text=True ) print("------------------------------------------") print(ps.stdout) print("------------------------------------------") # 选择其中一种方式即可 # reader = csv.reader(ps.stdout.splitlines()) reader = csv.reader(io.StringIO(ps.stdout)) for row in reader: print(row) exit(0)
内容的提问来源于stack exchange,提问作者mbmast
相关产品推荐
相关产品推荐

