[javascript] 이진 NodeJS 버퍼를 JavaScript ArrayBuffer로 변환

NodeJS 바이너리 버퍼를 JavaScript ArrayBuffer로 어떻게 변환 할 수 있습니까?



답변

의 인스턴스 BufferUint8Array node.js 4.x 이상의 인스턴스입니다 . 따라서 가장 효율적인 솔루션은 https://stackoverflow.com/a/31394257/1375574에 따라 buf.buffer속성에 직접 액세스하는 것 입니다. Buffer 생성자는 다른 방향으로 이동해야하는 경우 ArrayBufferView 인수도 사용합니다.

이렇게하면 복사본이 만들어지지 않습니다. 즉, ArrayBufferView에 쓰면 원래 Buffer 인스턴스에 쓰입니다.


이전 버전에서 node.js에는 v8의 일부로 ArrayBuffer가 모두 있지만 Buffer 클래스는보다 유연한 API를 제공합니다. 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에서 버퍼로 :

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


답변

종속성 없음, 가장 빠른 Node.js 4.x 이상

BufferUint8Arrays이므로 백업 영역을 슬라이스 (복사)하면 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의 (기본적으로 이하 4 KB, 절반 풀 크기가 ) 공유에 전망 할 수있다 ArrayBuffer. 슬라이스하지 않으면 ArrayBuffer다른 데이터를 포함하는 데이터로 끝날 수 있습니다 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);

Node.js의 모든 의존성, 적당한 속도 없음

O (n) 시간에 실행되는 Martin Thomson의 답변을 사용하십시오 . (최적화에 대한 그의 답변에 대한 의견에 대한 내 답변을 참조하십시오. DataView 사용은 느립니다. 바이트를 뒤집어 야하는 경우에도 더 빠른 방법이 있습니다.)

종속성, 빠름, Node.js ≤ 0.12 또는 iojs 3.x

https://www.npmjs.com/package/memcpy 를 사용 하여 어느 방향 으로든 이동할 수 있습니다 (Buffer to ArrayBuffer 및 back). 여기에 게시 된 다른 답변보다 빠르며 잘 작성된 라이브러리입니다. (참조의에게 포크를 ngossen 필요 3.x를 iojs을 통해 노드 0.12 ).


답변

“ArrayBuffer에서 버퍼로”는 다음과 같이 수행 할 수 있습니다.

var buffer = Buffer.from( new Uint8Array(ab) );


답변

작성하는 더 빠른 방법

var arrayBuffer = new Uint8Array(nodeBuffer).buffer;

그러나 이는 1024 개의 요소가있는 버퍼에서 제안 된 toArrayBuffer 함수보다 약 4 배 느리게 실행되는 것으로 보입니다.


답변

1. A Buffer는 을 살펴 보기 위한 보기 일뿐 ArrayBuffer입니다.

A는 Buffer, 사실,이며 FastBuffer, 이는 extends(로부터 상속)를 Uint8Array옥텟 단위 인 실제 메모리, 중 ( “부분적인 접근은”) ArrayBuffer.

  ? Node.js를 9.4.0/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;

2.의 크기 ArrayBuffer보기 의 크기 는 다를 수 있습니다.

이유 # 1 : Buffer.from(arrayBuffer[, byteOffset[, length]]).

을 사용하면 기본 및 뷰의 위치와 크기 를 지정하여을 Buffer.from(arrayBuffer[, byteOffset[, length]])만들 수 있습니다 .BufferArrayBuffer

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.

이유 # 2 : FastBuffer의 메모리 할당.

크기에 따라 두 가지 다른 방식으로 메모리를 할당합니다.

  • 크기가 메모리 풀 크기의 절반보다 작고 0이 아닌 경우 ( “작음”) : 메모리 풀 을 사용 하여 필요한 메모리를 준비합니다.
  • 그렇지 않으면 : ArrayBuffer필요한 메모리에 정확히 맞는 전용 을 만듭니다 .

  ? Node.js를 9.4.0/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의 크기는 기본적으로 8KiB이며에 지정되어 Buffer.poolSize있습니다. a에 작은 크기의 메모리 청크를 제공하려는 Buffer경우 마지막 메모리 풀에이를 처리 할 수있는 충분한 메모리가 있는지 확인합니다. 그렇다면 메모리 풀의 주어진 부분 청크 Buffer“보는” 것을 생성하고, 그렇지 않으면 새로운 메모리 풀을 생성합니다.


의 기본 ArrayBuffer에 액세스 할 수 있습니다 Buffer. Bufferbuffer재산 에서 상속 (Uint8Array )를 보유하고 있습니다. “작은”속성은입니다 전체 메모리 풀을 나타냅니다. 따라서이 경우에는 및의 크기 가 다릅니다. BufferbufferArrayBufferArrayBufferBuffer

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.

3. 따라서“ 보기 ”메모리를 추출해야합니다 .

ArrayBuffer크기는 고정되어 있으므로 부품을 복사하여 추출해야합니다. 이를 위해 우리는 BufferbyteOffsetpropertylengthproperty 를 사용합니다.Uint8Array방법 의 일부의 사본을 만든다 . 여기에서 -ing 방법은 @ZachB 에서 영감을 얻었습니다 .ArrayBuffer.prototype.sliceArrayBufferslice()

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

4. 성능 향상

결과를 읽기 전용으로 사용하거나 입력을 수정해도 괜찮은 경우 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


답변

다음과 같은 우수한 npm 패키지를 사용하십시오 to-arraybuffer.

또는 직접 구현할 수 있습니다. 버퍼가 호출 buf되면 다음을 수행하십시오.

buf.buffer.slice(buf.byteOffset, buf.byteOffset + buf.byteLength)


답변

당신은 ArrayBuffer유형으로 생각할 수 있습니다 Buffer.

ArrayBuffer그러므로 항상 유형 (소위 “배열 버퍼보기”)를 필요로한다. 일반적으로 배열 버퍼보기 의 유형은 Uint8Array또는 Uint16Array입니다.

Renato Mangini 의 ArrayBuffer와 String 간의 변환 에 대한 좋은 기사가 있습니다 .

코드 예제 (Node.js의 경우)에서 필수 부분을 요약했습니다. 또한 typed ArrayBuffer와 untyped 사이를 변환하는 방법을 보여줍니다 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!"