在字符串和 ArrayBuffers 之间转换

新手上路,请多包涵

是否有一种普遍接受的技术可以有效地将 JavaScript 字符串转换为 ArrayBuffers ,反之亦然?具体来说,我希望能够将 ArrayBuffer 的内容写入 localStorage 并将其读回。

原文由 kpozin 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 3.3k
2 个回答

2016 年更新- 五年过去了,现在规范中有新的方法(参见下面的支持),可以使用正确的编码在字符串和类型化数组之间进行转换。

文本编码器

TextEncoder 表示

TextEncoder 接口代表特定方法的编码器,

那是一种特定的字符编码,例如 utf-8iso-8859-2koi8

cp1261 , gbk , …编码器将代码点流作为输入,并

发出一个字节流。

自上述内容编写以来的更改说明:( 同上)

注意:Firefox、Chrome 和 Opera 曾经支持编码

utf-8 以外的类型(例如 utf-16、iso-8859-2、koi8、cp1261 和

国标)。从 Firefox 48 […]、Chrome 54 […] 和 Opera 41 开始,没有

utf-8 以外的其他编码类型可用,以便匹配

规格*

*) 更新了规格(W3) 和 此处(whatwg)。

创建 TextEncoder 的实例后,它将接受一个字符串并使用给定的编码参数对其进行编码:

 if (!("TextEncoder" in window))
 alert("Sorry, this browser does not support TextEncoder...");

 var enc = new TextEncoder(); // always utf-8
 console.log(enc.encode("This is a string converted to a Uint8Array"));

如果需要,您当然可以在结果 Uint8Array 上使用 .buffer 参数将底层 ArrayBuffer 转换为不同的视图。

只需确保字符串中的字符符合编码模式,例如,如果您在示例中使用 UTF-8 范围之外的字符,它们将被编码为两个字节而不是一个字节。

对于一般用途,您可以对 localStorage 之类的内容使用 UTF-16 编码。

文本解码器

同样,相反的过程 使用 TextDecoder

TextDecoder 接口代表特定方法的解码器,

那是一种特定的字符编码,例如 utf-8iso-8859-2koi8

cp1261 , gbk , … 解码器将字节流作为输入并发出

一个代码点流。

所有可用的解码类型都可以在 这里 找到。

 if (!("TextDecoder" in window))
 alert("Sorry, this browser does not support TextDecoder...");

 var enc = new TextDecoder("utf-8");
 var arr = new Uint8Array([84,104,105,115,32,105,115,32,97,32,85,105,110,116,
 56,65,114,114,97,121,32,99,111,110,118,101,114,116,
 101,100,32,116,111,32,97,32,115,116,114,105,110,103]);
 console.log(enc.decode(arr));

MDN StringView 库

这些的替代方法是使用 StringView(许可为 lgpl-3.0),其目标是:

  • 基于

JavaScript ArrayBuffer 接口

  • 创建一个高度可扩展的库,任何人都可以通过向对象 StringView.prototype 添加方法来扩展它

  • 为此类字符串对象(从现在开始:stringViews)创建一组方法,这些对象严格在数字数组上工作

而不是创建新的不可变 JavaScript 字符串

  • 使用 JavaScript 的默认 UTF-16 DOMStrings 以外的 Unicode 编码

提供更多的灵活性。但是,在现代浏览器中内置 TextEncoder / TextDecoder 时,我们需要链接或嵌入这个库。

支持

截至 2018 年 7 月:

TextEncoder (实验性,在标准轨道上)

 Chrome | Edge | Firefox | IE | Opera | Safari
 ----------|-----------|-----------|-----------|-----------|-----------
 38 | ? | 19° | - | 25 | -

 Chrome/A | Edge/mob | Firefox/A | Opera/A |Safari/iOS | Webview/A
 ----------|-----------|-----------|-----------|-----------|-----------
 38 | ? | 19° | ? | - | 38

 °) 18: Firefox 18 implemented an earlier and slightly different version
 of the specification.

 WEB WORKER SUPPORT:

 Experimental, On Standard Track

 Chrome | Edge | Firefox | IE | Opera | Safari
 ----------|-----------|-----------|-----------|-----------|-----------
 38 | ? | 20 | - | 25 | -

 Chrome/A | Edge/mob | Firefox/A | Opera/A |Safari/iOS | Webview/A
 ----------|-----------|-----------|-----------|-----------|-----------
 38 | ? | 20 | ? | - | 38

 Data from MDN - `npm i -g mdncomp` by epistemex

原文由 user1693593 发布,翻译遵循 CC BY-SA 4.0 许可协议

尽管使用 Blob/FileReader 的 Dennis 和 gengkev 解决方案有效,但我不建议采用这种方法。它是解决简单问题的异步方法,比直接解决方案慢得多。我在 html5rocks 中发表了一篇文章,其中包含一个更简单(更快)的解决方案: http ://updates.html5rocks.com/2012/06/How-to-convert-ArrayBuffer-to-and-from-String

解决方案是:

 function ab2str(buf) {
  return String.fromCharCode.apply(null, new Uint16Array(buf));
}

function str2ab(str) {
  var buf = new ArrayBuffer(str.length*2); // 2 bytes for each char
  var bufView = new Uint16Array(buf);
  for (var i=0, strLen=str.length; i<strLen; i++) {
    bufView[i] = str.charCodeAt(i);
  }
  return buf;
}


编辑:

Encoding API 有助于解决字符串转换 问题。查看 Jeff Posnik 在 Html5Rocks.com 上对上述原始文章的回复。

摘抄:

编码 API 使原始字节和原生 JavaScript 字符串之间的转换变得简单,无论您需要使用许多标准编码中的哪一种。

 <pre id="results"></pre>

<script>
  if ('TextDecoder' in window) {
    // The local files to be fetched, mapped to the encoding that they're using.
    var filesToEncoding = {
      'utf8.bin': 'utf-8',
      'utf16le.bin': 'utf-16le',
      'macintosh.bin': 'macintosh'
    };

    Object.keys(filesToEncoding).forEach(function(file) {
      fetchAndDecode(file, filesToEncoding[file]);
    });
  } else {
    document.querySelector('#results').textContent = 'Your browser does not support the Encoding API.'
  }

  // Use XHR to fetch `file` and interpret its contents as being encoded with `encoding`.
  function fetchAndDecode(file, encoding) {
    var xhr = new XMLHttpRequest();
    xhr.open('GET', file);
    // Using 'arraybuffer' as the responseType ensures that the raw data is returned,
    // rather than letting XMLHttpRequest decode the data first.
    xhr.responseType = 'arraybuffer';
    xhr.onload = function() {
      if (this.status == 200) {
        // The decode() method takes a DataView as a parameter, which is a wrapper on top of the ArrayBuffer.
        var dataView = new DataView(this.response);
        // The TextDecoder interface is documented at http://encoding.spec.whatwg.org/#interface-textdecoder
        var decoder = new TextDecoder(encoding);
        var decodedString = decoder.decode(dataView);
        // Add the decoded file's text to the <pre> element on the page.
        document.querySelector('#results').textContent += decodedString + '\n';
      } else {
        console.error('Error while requesting', file, this);
      }
    };
    xhr.send();
  }
</script>

原文由 mangini 发布,翻译遵循 CC BY-SA 3.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题