記一次nodejs使用require('child_process').spawn調用.bat/.cmd腳本遇到的中文亂碼問題

根據客戶須要開發了一個先後端程序,大概流程以下:html

  1. 雙擊start.cmd啓動nodejs服務器;
  2. 用戶在web頁面填寫部分參數,提交到後臺;
  3. 後端使用nodejs接收前端參數,而後根據參數複寫服務器上的配置文件;
  4. 以後使用require('child_process').spawn調用服務器上的批處理腳本;
  5. 腳本中調用了ANSYS的可執行文件compute.bat來計算、轉換3D模型數據;
  6. 可執行文件compute.bat執行過程當中會輸出一些運行提示文本到一個臨時文件temp.dat中,提示文本中包含有中文;
  7. 使用nodejs監聽臨時文件的變更,從中提取出提示文本;
  8. 使用WebSocket像前端推送這些提示文本,而後前端展現在界面上。

start.cmd執行:
image.png前端

web頁面參數:
image.pngnode

臨時文件temp.dat內容:
image.pngweb

客戶端收到WebSocket消息後展現如:
image.png後端

整個流程中,一、七、8環節都有中文字符服務器

  • 啓動nodejs服務器的命令提示符窗口中的標題,運行過程打印的提示文本;
  • compute.bat執行過程輸出到temp.dat中的文本;
  • nodejs讀取temp.dat中的文本。

首先,start.cmd、compute.bat、temp.dat文件自己有相應的編碼,這些批處理文件保存的編碼會影響輸出文本的編碼。ui

首先start.cmd是我用建立的,編碼爲UTF-8,雙擊文件打開後,
image.png
文件內容編碼

@ECHO OFF
title 啓動服務器
node ./index.js
pause

雙擊start.cmd時,是調用了cmd.exe命令提示符執行裏面的腳本,而命令提示符自己也有本身的編碼方式,能夠輸入chcp命令查看:
image.pngspa

活動代碼頁: 936

936就表示命令提示符使用的GBK編碼方式,而start.cmd文件使用的UTF-8,兩者不一致致使了亂碼,因此解決的方式就是使兩者保持一致,兩種修改方式:.net

  1. 將start.cmd從新以GBK編碼方式保存;
  2. 修改命令提示符的編碼方式爲UTF-8,傳送門——設置CMD默認代碼頁爲65001或936

此時,雙擊start.cmd,標題就正常顯示了
image.png

因爲compute.bat是客戶提供的,temp.dat是compute.bat生成的,這兩個編碼是一致的,都是ANSI(ANSI是Windows獨有的,嚴格來講不能稱之爲編碼類型,傳送門——ANSI是什麼編碼?)。ANSI在國內通常就是GBK編碼。

在使用nodejs讀取temp.dat內容的時候,因爲temp.dat是GBK編碼,因此有以下代碼:

var fs = require("fs");
var iconv = require('iconv-lite');

var result = fs.readFileSync("temp.dat", "binary");
var text = iconv.decode(Buffer.from(result, "binary"), "GBK");
console.log("【原有內容】" + text);

nodejs自己不支持GBK,這裏用到了iconv-lite模塊來從讀取到的Buffer以GBK方式解碼,結果正常展現:
image.png

這裏,有三個地方的編碼須要保持一致:temp.dat、nodejs處理的編碼方式、命令提示符的編碼,不然展現在控制檯的中文就會亂碼。

因爲temp.dat是compute.bat腳本生成的,而compute.bat腳本文件自己以何種編碼方式保存會影響輸出的編碼,這一點也是不能忽略的。

另外,compute.bat執行過程發生的錯誤,若是nodejs捕獲到了,也是須要使用GBK方式進行解碼的:

var {spawn } = require('child_process');

  const bat = spawn('cmd.exe', ['/c', "compute.bat"], {
    encoding: "buffer"
  });

  bat.stderr.on('data', (stderr) => {
    var errStr = iconv.decode(Buffer.from(stderr, "binary"), "GBK");
    console.error(errStr);
  });

  bat.on('exit', (code) => {
    if (code === 0) {
      // 正常退出
      cb();
    } else {
      cb({ code: code });
    }
  });

因爲第一次使用nodejs操做文件構建稍微複雜點的程序,踩了不少坑,這篇文章主要針對過程當中的編碼問題簡單介紹。也是第一回在思否發稍微長點的文章,文筆粗糙,各位不喜勿噴。

相關文章
相關標籤/搜索