如何从 Blob 转到 ArrayBuffer
Posted
技术标签:
【中文标题】如何从 Blob 转到 ArrayBuffer【英文标题】:How to go from Blob to 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 完成。
【参考方案1】:
您可以使用FileReader
将Blob
读取为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://***.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.result
与 this.result
的提示
参考:
https://developer.mozilla.org/en-US/docs/Web/API/FileReader#readAsArrayBuffer() https://www.w3.org/TR/FileAPI/#dfn-readAsArrayBuffer【讨论】:
这看起来不是很多代码.. 应该很简单吗? @HenleyChiu 我编辑了答案以包含代码的简短版本。较长的示例旨在完全自包含(显示如何创建 ArrayBuffer、Blob 并再次返回)。在不使用 Web Worker 和 FileReaderSync 的情况下,我无法找到一种同步方式来读取 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 以启用安全的一面;)
【讨论】:
聪明的技巧,不要与Blob.arrayBuffer()
混淆,即使在2020年,caniuse.com/#feat=mdn-api_blob_arraybuffer或developer.mozilla.org/en-US/docs/Web/API/Blob/arrayBuffer实际上兼容性也很差
这个性能怎么样?它是复制 Blob 中的数据还是只返回它的视图?
@GaryO 没有对它进行基准测试,我认为它会复制 blob 并返回它的视图。
叹息,它似乎确实复制了。如果 blob 很大,那就不好了!
仅供参考 await blob.arrayBuffer()
现在有很好的支持:developer.mozilla.org/en-US/docs/Web/API/Blob/…【参考方案3】:
或者你可以使用 fetch API
fetch(URL.createObjectURL(myBlob)).then(res => res.arrayBuffer())
我不知道性能差异是什么,这也会显示在 DevTools 的网络选项卡上。
【讨论】:
或者只是new Response(blob).arrayBuffer()
或await blob.arrayBuffer()
,现在有很好的支持:developer.mozilla.org/en-US/docs/Web/API/Blob/…【参考方案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()
【讨论】:
***.com/a/51758200/3702797 和所有其他后备都已经存在。 @Kaiido,见***.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
)();
【讨论】:
很遗憾目前在 Safari 中无法使用(还) @HerrZatacke,看看我的回答 根据developer.mozilla.org/en-US/docs/Web/API/Blob/… Safari 14+ 版本支持此 API。【参考方案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);
);
【讨论】:
以上是关于如何从 Blob 转到 ArrayBuffer的主要内容,如果未能解决你的问题,请参考以下文章
关于blob转到目标库报ORA-01461: 仅能绑定要插入 LONG 列的 LONG 值错误解决方案