使用Node.js处理前端代码文件的编码问题


Posted in Javascript onFebruary 16, 2016

使用 NodeJS 编写前端工具时,操作得最多的是文本文件,因此也就涉及到了文件编码的处理问题。我们常用的文本编码有 UTF8 和 GBK 两种,并且 UTF8 文件还可能带有 BOM。在读取不同编码的文本文件时,需要将文件内容转换为 JS 使用的 UTF8 编码字符串后才能正常处理。

BOM 的移除
BOM 用于标记一个文本文件使用 Unicode 编码,其本身是一个 Unicode 字符("\uFEFF"),位于文本文件头部。在不同的 Unicode 编码下,BOM 字符对应的二进制字节如下:

Bytes   Encoding
----------------------------
  FE FF    UTF16BE
  FF FE    UTF16LE
  EF BB BF  UTF8

因此,我们可以根据文本文件头几个字节等于啥来判断文件是否包含 BOM,以及使用哪种 Unicode 编码。但是,BOM 字符虽然起到了标记文件编码的作用,其本身却不属于文件内容的一部分,如果读取文本文件时不去掉 BOM,在某些使用场景下就会有问题。例如我们把几个 JS 文件合并成一个文件后,如果文件中间含有 BOM 字符,就会导致浏览器 JS 语法错误。因此,使用 NodeJS 读取文本文件时,一般需要去掉 BOM。例如,以下代码实现了识别和去除 UTF8 BOM 的功能。

function readText(pathname) {
  var bin = fs.readFileSync(pathname);

  if (bin[0] === 0xEF && bin[1] === 0xBB && bin[2] === 0xBF) {
    bin = bin.slice(3);
  }

  return bin.toString('utf-8');
}

GBK 转 UTF8
NodeJS 支持在读取文本文件时,或者在 Buffer 转换为字符串时指定文本编码,但遗憾的是,GBK 编码不在NodeJS自身支持范围内。因此,一般我们借助 iconv-lite 这个三方包来转换编码。使用 NPM 下载该包后,我们可以按下边方式编写一个读取 GBK 文本文件的函数。

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

function readGBKText(pathname) {
  var bin = fs.readFileSync(pathname);

  return iconv.decode(bin, 'gbk');
}

单字节编码
有时候,我们无法预知需要读取的文件采用哪种编码,因此也就无法指定正确的编码。比如我们要处理的某些 CSS 文件中,有的用 GBK 编码,有的用 UTF8 编码。虽然可以一定程度可以根据文件的字节内容猜测出文本编码,但这里要介绍的是有些局限,但是要简单得多的一种技术。

首先我们知道,如果一个文本文件只包含英文字符,比如 Hello World,那无论用 GBK 编码或是 UTF8 编码读取这个文件都是没问题的。这是因为在这些编码下,ASCII0~128 范围内字符都使用相同的单字节编码。

反过来讲,即使一个文本文件中有中文等字符,如果我们需要处理的字符仅在 ASCII0~128 范围内,比如除了注释和字符串以外的JS代码,我们就可以统一使用单字节编码来读取文件,不用关心文件的实际编码是 GBK 还是 UTF8。以下示例说明了这种方法。

1. GBK编码源文件内容:

var foo = '中文';

2. 对应字节:

76 61 72 20 66 6F 6F 20 3D 20 27 D6 D0 CE C4 27 3B

3. 使用单字节编码读取后得到的内容:

var foo = '{乱码}{乱码}{乱码}{乱码}';

4. 替换内容:

var bar = '{乱码}{乱码}{乱码}{乱码}';

5. 使用单字节编码保存后对应字节:

76 61 72 20 62 61 72 20 3D 20 27 D6 D0 CE C4 27 3B

6. 使用 GBK 编码读取后得到内容:

var bar = '中文';

这里的诀窍在于,不管大于 0xEF 的单个字节在单字节编码下被解析成什么乱码字符,使用同样的单字节编码保存这些乱码字符时,背后对应的字节保持不变。

NodeJS 中自带了一种 binary 编码可以用来实现这个方法,因此在下例中,我们使用这种编码来演示上例对应的代码该怎么写。

function replace(pathname) {
  var str = fs.readFileSync(pathname, 'binary');
  str = str.replace('foo', 'bar');
  fs.writeFileSync(pathname, str, 'binary');
}
Javascript 相关文章推荐
URL编码转换,escape() encodeURI() encodeURIComponent()
Dec 27 Javascript
Prototype使用指南之range.js
Jan 10 Javascript
在线编辑器的实现原理(兼容IE和FireFox)
Mar 09 Javascript
Textarea与懒惰渲染实现代码
Jan 04 Javascript
Jquery中LigerUi的弹出编辑框(实现方法)
Jul 09 Javascript
JavaScript中的函数模式详解
Feb 11 Javascript
深入浅析Bootstrap列表组组件
May 03 Javascript
JS碰撞运动实现方法详解
Dec 15 Javascript
JS实现中国公民身份证号码有效性验证
Feb 20 Javascript
JS 组件系列之Bootstrap Table的冻结列功能彻底解决高度问题
Jun 30 Javascript
解决Vue2.0中使用less给元素添加背景图片出现的问题
Sep 03 Javascript
Vue组件跨层级获取组件操作
Jul 27 Javascript
让图片跳跃起来  javascript图片轮播特效
Feb 16 #Javascript
Node.js本地文件操作之文件拷贝与目录遍历的方法
Feb 16 #Javascript
详解Node.js包的工程目录与NPM包管理器的使用
Feb 16 #Javascript
javascript每日必学之运算符
Feb 16 #Javascript
解析Node.js基于模块和包的代码部署方式
Feb 16 #Javascript
javascript每日必学之基础入门
Feb 16 #Javascript
快速掌握Node.js环境的安装与运行方法
Feb 16 #Javascript
You might like
php操作csv文件代码实例汇总
2014/09/22 PHP
主流PHP框架的优缺点对比分析
2014/12/25 PHP
Thinkphp关闭缓存的方法
2015/06/26 PHP
PHP+mysql+ajax轻量级聊天室实现方法详解
2016/10/17 PHP
js使用eval解析json实例与注意事项分享
2014/01/18 Javascript
非常实用的12个jquery代码片段
2015/11/02 Javascript
vue2.0父子组件及非父子组件之间的通信方法
2017/01/21 Javascript
js eval函数使用,js对象和字符串互转实例
2017/03/06 Javascript
js中json对象和字符串的理解及相互转化操作实现方法
2017/09/22 Javascript
解决VUE中document.body.scrollTop为0的问题
2018/09/15 Javascript
微信小程序全局变量GLOBALDATA的定义和调用过程解析
2019/09/23 Javascript
node.js如何根据URL返回指定的图片详解
2020/10/21 Javascript
Python实现的当前时间多加一天、一小时、一分钟操作示例
2018/05/21 Python
python爱心表白 每天都是浪漫七夕!
2018/08/18 Python
python爬虫爬取笔趣网小说网站过程图解
2019/11/18 Python
浅谈python已知元素,获取元素索引(numpy,pandas)
2019/11/26 Python
Python3.7基于hashlib和Crypto实现加签验签功能(实例代码)
2019/12/04 Python
Python解释器及PyCharm工具安装过程
2020/02/26 Python
python GUI库图形界面开发之PyQt5菜单栏控件QMenuBar的详细使用方法与实例
2020/02/28 Python
Django 再谈一谈json序列化
2020/03/16 Python
Python子进程subpocess原理及用法解析
2020/07/16 Python
css3实现文字首尾衔接跑马灯的示例代码
2020/10/16 HTML / CSS
Myprotein台湾官方网站:全球领先的运动营养品牌
2018/12/10 全球购物
2014年两会学习心得范例
2014/03/17 职场文书
大学生党员自我评价范文
2014/04/09 职场文书
桥梁工程专业求职信
2014/04/21 职场文书
主持人演讲稿
2014/05/13 职场文书
不听老师话的万能检讨书
2014/10/04 职场文书
现役军人家属慰问信
2015/03/24 职场文书
新郎新娘致辞
2015/07/31 职场文书
公文写作:工伤事故分析报告怎么写?
2019/11/05 职场文书
python 字典和列表嵌套用法详解
2021/06/29 Python
Python基础数据类型tuple元组的概念与用法
2021/08/02 Python
Java字符缓冲流BufferedWriter
2022/04/09 Java/Android
Python Matplotlib绘制两个Y轴图像
2022/04/13 Python
ssh服务器拒绝了密码 请再试一次已解决(亲测有效)
2022/08/14 Servers