最近遇到一个问题,拿到一个ArrayBuffer,知道它是以gb2312编码的文档,那么如何使用javascript从中解码出字符串。下面介绍常用的解决方案。
基础知识
字符编码
字符编码(英语:Character encoding)、字集码是把字符集中的字符编码为指定集合中某一对象(例如:比特模式、自然数序列、8位组或者电脉冲),以便文本在计算机中存储和通过通信网络的传递。常见的例子包括将拉丁字母表编码成摩斯电码和ASCII。其中,ASCII将字母、数字和其它符号编号,并用7比特的二进制来表示这个整数。通常会额外使用一个扩充的比特,以便于以1个字节的方式存储。
因此,如果不知道字符存储的编码方案,那么只能得到一堆无意义的数字,无法从中解码出正确的字符信息。
ArrayBuffer
ArrayBuffer对象、TypedArray对象、DataView对象是JavaScript操作二进制数据的一个接口。这些对象早就存在,属于独立的规格,ES6将它们纳入了ECMAScript规格,并且增加了新的方法。
这些对象原始的设计目的,与WebGL项目有关。所谓WebGL,就是指浏览器与显卡之间的通信接口,为了满足JavaScript与显卡之间大量的、实时的数据交换,它们之间的数据通信必须是二进制的,而不能是传统的文本格式。文本格式传递一个32位整数,两端的JavaScript脚本与显卡都要进行格式转化,将非常耗时。这时要是存在一种机制,可以像C语言那样,直接操作字节,将4个字节的32位整数,以二进制形式原封不动地送入显卡,脚本的性能就会大幅提升。
二进制数组就是在这种背景下诞生的。它很像C语言的数组,允许开发者以数组下标的形式,直接操作内存,大大增强了JavaScript处理二进制数据的能力,使得开发者有可能通过JavaScript与操作系统的原生接口进行二进制通信。
二进制数组由三个对象组成。
ArrayBuffer对象:代表内存之中的一段二进制数据,可以通过“视图”进行操作。“视图”部署了数组接口,这意味着,可以用数组的方法操作内存。
TypedArray对象:用来生成内存的视图,通过9个构造函数,可以生成9种数据格式的视图,比如Uint8Array(无符号8位整数)数组视图, Int16Array(16位整数)数组视图, Float32Array(32位浮点数)数组视图等等。
DataView对象:用来生成内存的视图,可以自定义格式和字节序,比如第一个字节是Uint8(无符号8位整数)、第二个字节是Int16(16位整数)、第三个字节是Float32(32位浮点数)等等。
简单说,ArrayBuffer对象代表原始的二进制数据,TypedArray对象代表确定类型的二进制数据,DataView对象代表不确定类型的二进制数据。它们支持的数据类型一共有9种(DataView对象支持除Uint8C以外的其他8种)。
解决方案
UTF-16的编码解码
下面的解决方案只能解码UTF-16编码的字符串,而且当ArrayBuffer的长度过大时,会报“ Maximum call stack size exceeded”的错误。
1 | function ab2str(buf) { |
gb2312解码
下面的解决方案能解码指定编码的字符串,包括utf-8,utf-16, iso-8859-2, koi8, cp1261, and gbk等。
1 | function ab2str(arrayBuf, encodeType) { |
参考链接
- How to convert ArrayBuffer to and from String,by Renato Mangini.
- 字符编码,by wikipedia.
- Converting arraybuffer to string : Maximum call stack size exceeded,by stackoverflow.
- “RangeError: Maximum call stack size exceeded” Why?,by stackoverflow.
- TextDecoder,by mozilla.
- String.fromCharCode(),by mozilla.
- 二进制数组,by 阮一峰.
- ArrayBuffer,by 阮一峰.