python

关注公众号 jb51net

关闭
首页 > 脚本专栏 > python > Python打开cmd.exe执行中文内容缺失/乱码

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个字节,对于双字节的 “传” 字:

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执行中文内容缺失/乱码的资料请关注脚本之家其它相关文章!

您可能感兴趣的文章:
阅读全文