如何将NodeJS二进制缓冲区转换为JavaScript ArrayBuffer?
Array
。因此,要存储许多浮点数,您需要Float32Array
占用4个字节的位置。而且,如果要将这些浮动对象快速序列化到文件中,则需要一个Buffer
,因为序列化为JSON需要很长时间。
如何将NodeJS二进制缓冲区转换为JavaScript ArrayBuffer?
Array
。因此,要存储许多浮点数,您需要Float32Array
占用4个字节的位置。而且,如果要将这些浮动对象快速序列化到文件中,则需要一个Buffer
,因为序列化为JSON需要很长时间。
Answers:
的实例Buffer
也是Uint8Array
node.js 4.x及更高版本中的实例。因此,最有效的解决方案是buf.buffer
按照https://stackoverflow.com/a/31394257/1375574直接访问属性。如果您需要其他方向,则Buffer构造函数还可以使用ArrayBufferView参数。
请注意,这不会创建副本,这意味着对任何ArrayBufferView的写操作都将写入原始Buffer实例。
从Buffer到ArrayBuffer:
function toArrayBuffer(buf) {
var ab = new ArrayBuffer(buf.length);
var view = new Uint8Array(ab);
for (var i = 0; i < buf.length; ++i) {
view[i] = buf[i];
}
return ab;
}
从ArrayBuffer到Buffer:
function toBuffer(ab) {
var buf = Buffer.alloc(ab.byteLength);
var view = new Uint8Array(ab);
for (var i = 0; i < buf.length; ++i) {
buf[i] = view[i];
}
return buf;
}
size&0xfffffffe
复制32位整数,然后,如果剩余1个字节,则复制8位整数;如果2个字节,则复制16位整数;如果3个字节,则复制16位和8位整数。
ab
退货?有什么不干的ab
?我总是得到{}
结果。
slice()
方法返回一个新ArrayBuffer
内容,该内容的内容是ArrayBuffer
从开始(包括)到结束(不包括)的此字节的副本。” - MDNArrayBuffer.prototype.slice()
Buffer
s是Uint8Array
s,因此您只需要切片(复制)其后备区域ArrayBuffer
。
// Original Buffer
let b = Buffer.alloc(512);
// Slice (copy) its segment of the underlying ArrayBuffer
let ab = b.buffer.slice(b.byteOffset, b.byteOffset + b.byteLength);
在slice
和偏移的东西是需要,因为小Buffer
秒(小于4kB的默认状态下,一半的池大小)可以是在共享视图ArrayBuffer
。如果不进行切片,最终可能ArrayBuffer
包含来自another的数据Buffer
。请参阅文档中的说明。
如果最终需要一个TypedArray
,则可以创建一个而不复制数据:
// Create a new view of the ArrayBuffer without copying
let ui32 = new Uint32Array(b.buffer, b.byteOffset, b.byteLength / Uint32Array.BYTES_PER_ELEMENT);
使用Martin Thomson的答案,该答案运行时间为O(n)。(另请参阅我对他关于非优化问题的回答的评论。使用DataView速度很慢。即使需要翻转字节,也有更快的方法。)
您可以使用https://www.npmjs.com/package/memcpy沿任一方向运行(缓冲区到ArrayBuffer并返回)。它比此处发布的其他答案更快,并且是一个编写良好的库。节点通过0.12 3.X iojs需要ngossen的叉(见本)。
.byteLength
和.byteOffset
记录在哪里?
var ab = b.buffer.slice(b.byteOffset, b.byteOffset + b.byteLength);
拯救了我的一天
可以通过以下方式完成“从ArrayBuffer到Buffer”:
var buffer = Buffer.from( new Uint8Array(ab) );
一种更快的书写方式
var arrayBuffer = new Uint8Array(nodeBuffer).buffer;
但是,在具有1024个元素的缓冲区上,这似乎比建议的toArrayBuffer函数慢大约4倍。
Buffer
也的实例Uint8Array
中的Node.js 4.x和更高。对于较低的Node.js版本,您必须实现一个toArrayBuffer
功能。
Buffer
仅仅是一个视图用于寻找到的ArrayBuffer
。甲Buffer
,其实是一个FastBuffer
,它extends
(继承)Uint8Array
,这是一个八位位组单元视图的实际存储器,的(“局部存取”) ArrayBuffer
。
/lib/buffer.js#L65-L73
class FastBuffer extends Uint8Array {
constructor(arg1, arg2, arg3) {
super(arg1, arg2, arg3);
}
}
FastBuffer.prototype.constructor = Buffer;
internalBuffer.FastBuffer = FastBuffer;
Buffer.prototype = FastBuffer.prototype;
ArrayBuffer
和其视图的大小可能会有所不同。Buffer.from(arrayBuffer[, byteOffset[, length]])
。使用Buffer.from(arrayBuffer[, byteOffset[, length]])
,您可以创建一个,Buffer
并指定其基础ArrayBuffer
以及视图的位置和大小。
const test_buffer = Buffer.from(new ArrayBuffer(50), 40, 10);
console.info(test_buffer.buffer.byteLength); // 50; the size of the memory.
console.info(test_buffer.length); // 10; the size of the view.
FastBuffer
的内存分配。它根据大小以两种不同的方式分配内存。
ArrayBuffer
完全适合所需内存的专用磁盘。/lib/buffer.js#L306-L320
function allocate(size) {
if (size <= 0) {
return new FastBuffer();
}
if (size < (Buffer.poolSize >>> 1)) {
if (size > (poolSize - poolOffset))
createPool();
var b = new FastBuffer(allocPool, poolOffset, size);
poolOffset += size;
alignPool();
return b;
} else {
return createUnsafeBuffer(size);
}
}
📜Node.js 9.4.0/lib/buffer.js#L98-L100
function createUnsafeBuffer(size) {
return new FastBuffer(createUnsafeArrayBuffer(size));
}
甲存储器池是一个固定大小的预先分配用于保持小尺寸存储块用于存储块Buffer
秒。使用它可以将小型内存块紧密地保持在一起,因此可以防止由小型内存块的单独管理(分配和释放)引起的碎片。
在这种情况下,内存池ArrayBuffer
的默认大小为8 KiB(在中指定)Buffer.poolSize
。当要为提供一个较小的内存块时Buffer
,它将检查最后一个内存池是否有足够的可用内存来处理此内存;如果是的话,它会创建一个Buffer
该“意见”的内存池的给定的部分块,否则,将创建一个新的内存池等。
您可以访问底层ArrayBuffer
的Buffer
。该Buffer
的buffer
财产(即从继承Uint8Array
)持有它。一个“小” Buffer
的buffer
属性是ArrayBuffer
代表整个内存池。因此,在这种情况下,ArrayBuffer
和的Buffer
大小会有所不同。
const zero_sized_buffer = Buffer.allocUnsafe(0);
const small_buffer = Buffer.from([0xC0, 0xFF, 0xEE]);
const big_buffer = Buffer.allocUnsafe(Buffer.poolSize >>> 1);
// A `Buffer`'s `length` property holds the size, in octets, of the view.
// An `ArrayBuffer`'s `byteLength` property holds the size, in octets, of its data.
console.info(zero_sized_buffer.length); /// 0; the view's size.
console.info(zero_sized_buffer.buffer.byteLength); /// 0; the memory..'s size.
console.info(Buffer.poolSize); /// 8192; a memory pool's size.
console.info(small_buffer.length); /// 3; the view's size.
console.info(small_buffer.buffer.byteLength); /// 8192; the memory pool's size.
console.info(Buffer.poolSize); /// 8192; a memory pool's size.
console.info(big_buffer.length); /// 4096; the view's size.
console.info(big_buffer.buffer.byteLength); /// 4096; the memory's size.
console.info(Buffer.poolSize); /// 8192; a memory pool's size.
的ArrayBuffer
大小是固定的,因此我们需要通过复制零件来将其提取出来。要做到这一点,我们使用Buffer
的byteOffset
财产和length
财产,这是从继承Uint8Array
,并且该ArrayBuffer.prototype.slice
方法,这使得一个部分的副本ArrayBuffer
。slice()
本文中的-ing方法受@ZachB启发。
const test_buffer = Buffer.from(new ArrayBuffer(10));
const zero_sized_buffer = Buffer.allocUnsafe(0);
const small_buffer = Buffer.from([0xC0, 0xFF, 0xEE]);
const big_buffer = Buffer.allocUnsafe(Buffer.poolSize >>> 1);
function extract_arraybuffer(buf)
{
// You may use the `byteLength` property instead of the `length` one.
return buf.buffer.slice(buf.byteOffset, buf.byteOffset + buf.length);
}
// A copy -
const test_arraybuffer = extract_arraybuffer(test_buffer); // of the memory.
const zero_sized_arraybuffer = extract_arraybuffer(zero_sized_buffer); // of the... void.
const small_arraybuffer = extract_arraybuffer(small_buffer); // of the part of the memory.
const big_arraybuffer = extract_arraybuffer(big_buffer); // of the memory.
console.info(test_arraybuffer.byteLength); // 10
console.info(zero_sized_arraybuffer.byteLength); // 0
console.info(small_arraybuffer.byteLength); // 3
console.info(big_arraybuffer.byteLength); // 4096
如果要将结果用作只读,或者可以修改输入Buffer
的内容,则可以避免不必要的内存复制。
const test_buffer = Buffer.from(new ArrayBuffer(10));
const zero_sized_buffer = Buffer.allocUnsafe(0);
const small_buffer = Buffer.from([0xC0, 0xFF, 0xEE]);
const big_buffer = Buffer.allocUnsafe(Buffer.poolSize >>> 1);
function obtain_arraybuffer(buf)
{
if(buf.length === buf.buffer.byteLength)
{
return buf.buffer;
} // else:
// You may use the `byteLength` property instead of the `length` one.
return buf.subarray(0, buf.length);
}
// Its underlying `ArrayBuffer`.
const test_arraybuffer = obtain_arraybuffer(test_buffer);
// Just a zero-sized `ArrayBuffer`.
const zero_sized_arraybuffer = obtain_arraybuffer(zero_sized_buffer);
// A copy of the part of the memory.
const small_arraybuffer = obtain_arraybuffer(small_buffer);
// Its underlying `ArrayBuffer`.
const big_arraybuffer = obtain_arraybuffer(big_buffer);
console.info(test_arraybuffer.byteLength); // 10
console.info(zero_sized_arraybuffer.byteLength); // 0
console.info(small_arraybuffer.byteLength); // 3
console.info(big_arraybuffer.byteLength); // 4096
obtain_arraybuffer
:buf.buffer.subarray
似乎不存在。你的意思是buf.buffer.slice
这里吗?
ArrayBuffer.prototype.slice
它,后来将其修改为Uint8Array.prototype.subarray
。哦,我做错了。那时可能有点困惑。谢谢,现在一切都很好。
使用以下出色的npm软件包:to-arraybuffer
。
或者,您可以自己实现它。如果您的缓冲区被调用buf
,请执行以下操作:
buf.buffer.slice(buf.byteOffset, buf.byteOffset + buf.byteLength)
您可以将an ArrayBuffer
视为typed Buffer
。
一个ArrayBuffer
因此总是需要一个类型(即所谓“数组缓冲区视图”)。通常,数组缓冲区视图的类型为Uint8Array
或Uint16Array
。
Renato Mangini有一篇很好的文章介绍了如何在ArrayBuffer和String之间进行转换。
我已经在一个代码示例(针对Node.js)中总结了关键部分。它还显示了如何在类型化ArrayBuffer
和未类型化之间进行转换Buffer
。
function stringToArrayBuffer(string) {
const arrayBuffer = new ArrayBuffer(string.length);
const arrayBufferView = new Uint8Array(arrayBuffer);
for (let i = 0; i < string.length; i++) {
arrayBufferView[i] = string.charCodeAt(i);
}
return arrayBuffer;
}
function arrayBufferToString(buffer) {
return String.fromCharCode.apply(null, new Uint8Array(buffer));
}
const helloWorld = stringToArrayBuffer('Hello, World!'); // "ArrayBuffer" (Uint8Array)
const encodedString = new Buffer(helloWorld).toString('base64'); // "string"
const decodedBuffer = Buffer.from(encodedString, 'base64'); // "Buffer"
const decodedArrayBuffer = new Uint8Array(decodedBuffer).buffer; // "ArrayBuffer" (Uint8Array)
console.log(arrayBufferToString(decodedArrayBuffer)); // prints "Hello, World!"
我在Float64Array上尝试了上面的方法,但是它没有用。
我最终意识到,实际上需要按正确的块将数据“读入”视图。这意味着一次从源缓冲区读取8个字节。
无论如何,这就是我最终得到的...
var buff = new Buffer("40100000000000004014000000000000", "hex");
var ab = new ArrayBuffer(buff.length);
var view = new Float64Array(ab);
var viewIndex = 0;
for (var bufferIndex=0;bufferIndex<buff.length;bufferIndex=bufferIndex+8) {
view[viewIndex] = buff.readDoubleLE(bufferIndex);
viewIndex++;
}
Buffer.read*
方法都是缓慢的,也。
该代理将缓冲区公开为TypedArrays中的任何一个,没有任何副本。:
https://www.npmjs.com/package/node-buffer-as-typedarray
它仅适用于LE,但可以轻松移植到BE。同样,永远也不必实际测试这种方法的效率。
现在有一个非常有用的npm软件包:https : buffer
//github.com/feross/buffer
它尝试提供与节点的Buffer API 100%相同的API,并允许:
还有更多。
我已经将我的节点更新到版本5.0.0,并且我正在使用此版本:
function toArrayBuffer(buffer){
var array = [];
var json = buffer.toJSON();
var list = json.data
for(var key in list){
array.push(fixcode(list[key].toString(16)))
}
function fixcode(key){
if(key.length==1){
return '0'+key.toUpperCase()
}else{
return key.toUpperCase()
}
}
return array
}
我用它来检查我的vhd磁盘映像。
toArrayBuffer(new Buffer([1,2,3]))
-> ['01', '02', '03']
-这将返回一个字符串数组,而不是整数/字节。