【问题标题】:How to go from Blob to ArrayBuffer如何从 Blob 转到 ArrayBuffer
【发布时间】:2013-02-26 19:49:19
【问题描述】:

我正在研究 Blob,我注意到当你有一个 ArrayBuffer 时,你可以很容易地将它转换为 Blob,如下所示:

var dataView = new DataView(arrayBuffer);
var blob = new Blob([dataView], { type: mimeString });

我现在的问题是,是否可以从 Blob 转到 ArrayBuffer?

【问题讨论】:

  • Blob 不是原生 JS 格式。它们就像对数据的引用,而不是实际数据。来自Blob 的数据无法直接读取,但可以通过一些 API 完成。

标签: javascript blob arraybuffer


【解决方案1】:

您可以使用FileReaderBlob 读取为ArrayBuffer

这是一个简短的例子:

var arrayBuffer;
var fileReader = new FileReader();
fileReader.onload = function(event) {
    arrayBuffer = event.target.result;
};
fileReader.readAsArrayBuffer(blob);

这是一个更长的例子:

// ArrayBuffer -> Blob
var uint8Array  = new Uint8Array([1, 2, 3]);
var arrayBuffer = uint8Array.buffer;
var blob        = new Blob([arrayBuffer]);

// Blob -> ArrayBuffer
var uint8ArrayNew  = null;
var arrayBufferNew = null;
var fileReader     = new FileReader();
fileReader.onload  = function(event) {
    arrayBufferNew = event.target.result;
    uint8ArrayNew  = new Uint8Array(arrayBufferNew);

    // warn if read values are not the same as the original values
    // arrayEqual from: http://stackoverflow.com/questions/3115982/how-to-check-javascript-array-equals
    function arrayEqual(a, b) { return !(a<b || b<a); };
    if (arrayBufferNew.byteLength !== arrayBuffer.byteLength) // should be 3
        console.warn("ArrayBuffer byteLength does not match");
    if (arrayEqual(uint8ArrayNew, uint8Array) !== true) // should be [1,2,3]
        console.warn("Uint8Array does not match");
};
fileReader.readAsArrayBuffer(blob);
fileReader.result; // also accessible this way once the blob has been read

这已在 Chrome 27-69、Firefox 20-60 和 Safari 6-11 的控制台中进行了测试。

这里还有一个你可以玩的现场演示:https://jsfiddle.net/potatosalad/FbaM6/

2018-06-23 更新:感谢 Klaus Klein 关于 event.target.resultthis.result 的提示

参考:

【讨论】:

  • 这看起来不是很多代码.. 应该很简单吗?
  • @HenleyChiu 我编辑了答案以包含代码的简短版本。较长的示例旨在完全自包含(显示如何创建 ArrayBuffer、Blob 并再次返回)。在不使用 Web WorkerFileReaderSync 的情况下,我无法找到一种同步方式来读取 Blob。
  • 有些人真的想证明回调地狱的存在。这对 LARGE blob 有意义,但对于正常用例,JavaScript 应该提供同步方法。
  • 仅供参考 await blob.arrayBuffer() 现在有很好的支持:developer.mozilla.org/en-US/docs/Web/API/Blob/…
【解决方案2】:

Response API 使用(不可变的)Blob,可以通过多种方式从中检索数据。 OP 只要求ArrayBuffer,这是它的演示。

var blob = GetABlobSomehow();

// NOTE: you will need to wrap this up in a async block first.
/* Use the await keyword to wait for the Promise to resolve */
await new Response(blob).arrayBuffer();   //=> <ArrayBuffer>

或者你可以使用这个:

new Response(blob).arrayBuffer()
.then(/* <function> */);

注意:API 与旧版(古代)浏览器不兼容,因此请查看Browser Compatibility Table 以启用安全的一面;)

【讨论】:

【解决方案3】:

或者你可以使用 fetch API

fetch(URL.createObjectURL(myBlob)).then(res => res.arrayBuffer())

我不知道性能差异是什么,这也会显示在 DevTools 的网络选项卡上。

【讨论】:

【解决方案4】:

只是为了补充@potatosalad 先生的回答。

您实际上不需要访问函数scope来获取onload回调的结果,您可以在event 参数:

var arrayBuffer;
var fileReader = new FileReader();
fileReader.onload = function(event) {
    arrayBuffer = event.target.result;
};
fileReader.readAsArrayBuffer(blob);

为什么这样更好?因为这样我们就可以在不丢失上下文的情况下使用箭头函数

var fileReader = new FileReader();
fileReader.onload = (event) => {
    this.externalScopeVariable = event.target.result;
};
fileReader.readAsArrayBuffer(blob);

【讨论】:

    【解决方案5】:

    await blob.arrayBuffer() 不错。

    问题是什么时候需要 iOS / Safari 支持.. 为此  需要this

    Blob.prototype.arrayBuffer ??=function(){ return new Response(this).arrayBuffer() }
    

    【讨论】:

    • stackoverflow.com/a/51758200/3702797 和所有其他后备都已经存在。
    • @Kaiido,见stackoverflow.com/questions/15341912/…。我的方法更优越,在 iOS 支持之前是必需的。 (之后可以简单地删除该行)
    • 而且 IE 中仍然需要 FileReader。我的观点是,您的答案没有提供比先前答案更多的东西。如果一个人想要构建一个 polyfill,那么执行相同任务的所有各种方法都已经存在。
    • @Kaiido,IE 要求很少见。 ¶ 是的,这是 polyfill 的唯一答案。
    【解决方案6】:

    now (Chrome 76+ & FF 69+) 有一个 Blob.prototype.arrayBuffer() 方法,它会返回一个 Promise 解析,ArrayBuffer 代表 Blob 的数据。

    (async () => {
      const blob = new Blob(['hello']);
      const buf = await blob.arrayBuffer();
      console.log( buf.byteLength ); // 5
    })();

    【讨论】:

    【解决方案7】:

    这是一个异步方法,它首先检查arrayBuffer 方法的可用性。此功能向后兼容且面向未来。

    async function blobToArrayBuffer(blob) {
        if ('arrayBuffer' in blob) return await blob.arrayBuffer();
        
        return new Promise((resolve, reject) => {
            const reader = new FileReader();
            reader.onload = () => resolve(reader.result);
            reader.onerror = () => reject;
            reader.readAsArrayBuffer(blob);
        });
    }
    

    【讨论】:

      猜你喜欢
      • 2017-10-24
      • 2013-07-17
      • 1970-01-01
      • 1970-01-01
      • 2021-08-24
      • 2011-12-08
      • 2015-10-12
      • 2015-07-15
      • 2020-06-12
      相关资源
      最近更新 更多