Python decode()处理bytes对象异常:返回空串或仅最后一行
subprocess.Popen读取输出解码异常(Windows环境)
问题重现
代码片段
output = process.stdout.readline() # 返回bytes对象 if output: print(str(output)) print(output.decode())
异常现象
仅显示最后一行
- bytes输出:
b'0M Scan C:\\Users\\Me\\Documents\\\r \r24 folders, 8 files, 65 bytes (1 KiB)' - decode()后输出:
24 folders, 8 files, 65 bytes (1 KiB) - 预期:
Scan C:\\Users\\Me\\Documents\\ 24 folders, 8 files, 65 bytes (1 KiB)
- bytes输出:
decode()返回空串
- bytes输出:
b'0%' - decode()后输出:空串
- 预期:
0%
- bytes输出:
原因分析
这是Windows命令行工具的输出特性导致的:
- 行覆盖问题:命令行工具常用
\r(回车符)实现行内容覆盖(比如扫描进度更新),解码后打印时,\r会将光标移到当前行开头,后续的空格会覆盖前面的0M Scan...内容,最后一个\r再移到行首,只显示最终的统计信息。 - 空串显示问题:实际输出的bytes大概率包含隐藏的
\r(比如b'0%\r'),打印时\r让光标回到行首,print自动添加的换行符会把0%覆盖,导致看起来是空串。
解决办法
方法1:手动处理回车符
解码后将\r替换为\n,让覆盖的内容转为换行显示:
output = process.stdout.readline() if output: decoded_str = output.decode().replace('\r', '\n').strip('\n') print(decoded_str)
方法2:让subprocess自动处理字符串和换行符
Python 3.7+可用text=True(旧版本用universal_newlines=True),让stdout直接返回字符串,无需手动解码,同时适配系统换行符,再处理\r即可:
import subprocess process = subprocess.Popen( ["你的命令"], stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True ) for line in process.stdout: cleaned_line = line.replace('\r', '\n').strip('\n') print(cleaned_line)
方法3:针对进度类输出的特殊处理
如果是持续输出的进度信息(比如0%这类),直接过滤掉\r保留核心内容:
output = process.stdout.readline() if output: decoded_str = output.decode().replace('\r', '').strip() print(decoded_str)
内容的提问来源于stack exchange,提问作者bikz
相关产品推荐
相关产品推荐

