Python打开cmd.exe执行命令后出现中文内容缺失/乱码的修复指南
作者:一世繁华行
WinExec调用cmd.exe总是丢中文,问题出在逐字节解码和编码不匹配上,本文教你用增量解码器+自动识别chcp编码,彻底解决乱码和丢字,让Python正确读取cmd中文输出,需要的朋友可以参考下
代码
打开cmd.exe接口:
self.__process = subprocess.Popen(
"cmd.exe",
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT
)
self.__cmd_pid = self.__process.pid
logger.debug(f'new console started')
读取内容:
out = self.__process.stdout.read(1)
if not out:
continue
out = out.decode("gbk", errors="ignore") if isinstance(out, bytes) else out
发送命令:
self.__process.stdin.write(f'{s}{line_break}'.encode("gbk"))
if flush:
self.__process.stdin.flush()
问题1:没读到中文字符
现象
发送命令:
ping www.baidu.com -S 172.16.10.11时cmd.exe实际显示:
正在 Ping www.a.shifen.com [153.3.238.28] 从 172.16.10.11 具有 32 字节的数据:
PING:传输失败。常见故障。
PING:传输失败。常见故障。
PING:传输失败。常见故障。
PING:传输失败。常见故障。
153.3.238.28 的 Ping 统计信息:
数据包: 已发送 = 4,已接收 = 0,丢失 = 4 (100% 丢失),
但实际读取到的内容为:
ping www.baidu.com -S 172.16.13.99
Ping www.a.shifen.com [124.237.178.35] 172.16.13.99 32 :
PING
PING
PING
PING
124.237.178.35 Ping :
: = 4 = 0 = 4 (100% )
问题定位
out = output_stream.stdout.read(1) # 每次只读取 1 个字节
out = out.decode("gbk", errors="ignore") # 用 GBK 解码,无法解码就丢弃
这里存在 两个问题:
1. 逐字节解码导致多字节字符丢失
中文字符在 GBK/UTF-8 中都是 多字节编码(GBK 占2字节,UTF-8 占3字节)。read(1) 每次只读 1个字节,对于双字节的 “传” 字:
- 第一次读到前导字节 \xd5,单独用 GBK decode + errors=“ignore” → 被判定为不完整序列 → 丢弃
- 第二次读到尾随字节 \xfd,单独 decode → 又丢弃
结果就是:所有中文全部被静默丢弃,只剩下单字节的英文字母、数字和符号。
2. 编码假设可能不匹配
代码硬编码使用 GBK 解码,但实际 adb shell 或现代 Windows 控制台输出的可能是 UTF-8。即便把 read(1) 改成批量读取,GBK 解码 UTF-8 字节流也同样会乱码或丢字。
验证
你可以在 Python 里验证这个现象:
>>> "传".encode("gbk")
b'\xb4\xab'
>>> b'\xb4'.decode("gbk", errors="ignore") # 只取第一个字节
'' # 直接丢了!
>>> b'\xab'.decode("gbk", errors="ignore") # 只取第二个字节
'' # 又丢了!
修复方案
使用 增量解码器 配合 UTF-8 编码(兼容性更好):
import codecs
# 在 __continuous_read_from_cmd_output 方法里
decoder = codecs.getincrementaldecoder("utf-8")(errors="replace")
while self.__thd_stop_event.is_set():
# ...
out = output_stream.stdout.read(1)
if not out:
continue
# 增量解码:自动处理多字节字符边界
char = decoder.decode(out)
if char: # 只有凑齐完整字符后才返回
...
补充:为什么直接看 cmd 窗口是正常的?
Windows 控制台(cmd 窗口)有自己的字符缓冲和编码处理机制,能正确组装多字节字符。而 WinExpect 是自己从 stdout 管道逐字节读、逐字节解码,没有做任何字节缓冲,所以把多字节中文拆碎了。
问题2:按问题1中的解决思路结局后,打印结果中又出现乱码
这说明编码选择不对——实际字节流是编码A,而我用编码B去解码,导致中文映射到了错误的 Unicode 码位上。
先在cme.exe窗口中输入:chcp,看打印结果,我的为936
活动代码页: 936
修复方案:
import codecs
# 在 __continuous_read_from_cmd_output 方法里
decoder = codecs.getincrementaldecoder("gbk")(errors="replace")
while self.__thd_stop_event.is_set():
# ...
out = output_stream.stdout.read(1)
if not out:
continue
# 增量解码:自动处理多字节字符边界
char = decoder.decode(out)
if char: # 只有凑齐完整字符后才返回
...
总结
chcp=936 → 用 GBK
chcp=65001 → 才用 UTF-8
无论用哪种编码,必须配合增量解码器(或至少按行读取),不能逐字节 decode
以上就是Python打开cmd.exe执行命令后出现中文内容缺失/乱码的修复指南的详细内容,更多关于Python打开cmd.exe执行中文内容缺失/乱码的资料请关注脚本之家其它相关文章!
