如何从 Blob 到 ArrayBuffer

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

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

我现在的问题是,有没有可能从一个 Blob 变成一个 ArrayBuffer?

184165 次浏览

可以使用 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 & mash; 69,Firefox 20 & mash; 60和 Safari 6 & mash; 11的控制台中进行了测试。

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

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

参考文献:

只是为了补充“土豆沙拉先生”的回答。

您实际上不需要访问函数 范围来获得 上传回调的结果,您可以自由地对 事件参数执行以下操作:

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);

或者可以使用提取 API

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

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

ResponseAPI 使用一个(不可变的) Blob,可以通过几种方式从中检索数据。操作室只要求 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> */);

注意: 这个 空气污染指数不兼容旧的(古老)浏览器,所以看看 浏览器兼容性表 是否安全;)

有一个 现在(Chrome76 + & FF 69 +)的 Prototype.arrayBuffer ()方法,它将用一个表示 Blob 数据的 ArrayBuffer 来返回一个  诺言解析。

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

await blob.arrayBuffer()正常。

问题是当 iOS/Safari 需要支持的时候,就需要 这个:

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

这是一个异步方法,它首先检查 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);
});
}