一、为什么在程序中用powershell执行命令会出现中文乱码,而在控件台却不会?
核心原因只有几个字:"编码 mismatch(不匹配)"。
这是 Windows 控制台的"旧习惯" 与 Node.js 的"新标准" 之间的一场冲突。
可以把它拆解为三个关键角色的"语言不通":
关键原因分析
1. Windows CMD/PowerShell 的"方言":GBK
在中文版的 Windows 系统中,CMD 和旧版 PowerShell 为了兼容老旧软件,默认使用的字符编码是 GBK(代码页 936)。
- 当你执行 dir 或 ping 时,系统内部生成的中文数据是按照 GBK 规则 编码的(比如"你好"这两个字,在 GBK 里是 C4E3 BAC3)。
2. Node.js 的"普通话":UTF-8
Node.js 是一个跨平台的现代运行时,它默认遵循国际标准,认为所有的输入输出流(Stream)都是 UTF-8 编码的。
- 当 Node.js 接收到 CMD 发来的数据时,它会本能地用 UTF-8 的规则 去解析。
3. 灾难性的"误读"
冲突就在这里发生了:
- CMD 发送了:C4E3 BAC3 (GBK 编码的"你好")
- Node.js 看到:C4E3 BAC3
- Node.js 心想:"这是 UTF-8 吗?让我查查表... 哎呀,这个字节组合在 UTF-8 里对应的是乱码符号(比如 浣犲ソ)。"
比喻一下:
这就好比 CMD 用中文 说了一句"你好",但 Node.js 戴着英文助听器听,结果听成了"# $ %&"。
为什么在终端直接运行没事?
- 原因:CMD 窗口(控制台宿主 conhost.exe)自己知道它是 GBK 环境。当它把结果显示在屏幕上时,它会自动把 GBK 数据画成汉字。
- 区别:当你用 Node.js 调用时,数据是通过管道(Pipe)传输的,Node.js 接管了数据流,但它没有自动切换成"中文助听器",导致它拿到的是原始字节,却用错误的规则去理解。
二、解决方法
既然知道了原因是 "GBK 源数据被误读为 UTF-8" ,解决办法就是**"在 Node.js 自动解码之前,拦截数据"**。
在代码(或重构后的代码)中,执行命令时必须加上一个关键配置:
1. 核心配置:encoding: 'buffer'
告诉 Node.js:"不要自作聪明地把数据转成字符串,把原始字节流(Buffer)给我,我自己来处理!"
2. 配合转码库:iconv-lite
拿到 Buffer 后,明确告诉它:"这是 GBK 编码的,请把它转成 UTF-8 字符串。"
代码示例:
javascript
const { exec } = require('child_process');
const iconv = require('iconv-lite');
// 关键点:设置 encoding: 'buffer'
exec('dir', { encoding: 'buffer' }, (error, stdout, stderr) => {
// 此时 stdout 和 stderr 还是二进制流 (Buffer)
// 我们手动用 GBK 解码,还原成正确的中文
const decodedStdout = iconv.decode(stdout, 'gbk');
const decodedStderr = iconv.decode(stderr, 'gbk');
console.log(decodedStdout); // 正常显示中文
});
三、总结
乱码不是因为代码写错,而是因为 Windows 默认用 GBK 输出,而 Node.js 默认用 UTF-8 接收。只要加上 encoding: 'buffer' 并手动转码,就能完美解决。
注:如果是用powershell执行命令,在命令前加chcp 65001; 那么返回的结果不用iconv-lite转码中文也能显示正常
chcp 65001 在系统层面设置活动代码页为UTF-8(65001是UTF-8的代码页编号)
chcp 65001 确保命令行输出使用UTF-8编码