【问题标题】:How to append bytes, multi-bytes and buffer to ArrayBuffer in javascript?如何在javascript中将字节、多字节和缓冲区附加到ArrayBuffer?
【发布时间】:2016-02-15 15:08:02
【问题描述】:

Javascript ArrayBuffer 或 TypedArrays 没有任何类型的 appendByte()、appendBytes() 或 appendBuffer() 方法。那么如果我想一次填充一个 ArrayBuffer 值,我该怎么做呢?

var firstVal = 0xAB;              // 1 byte
var secondVal = 0x3D7F            // 2 bytes
var anotherUint8Array = someArr;

var buffer = new ArrayBuffer();   // I don't know the length yet
var bufferArr = new UInt8Array(buffer);

// following methods do not exist. What are the alternatives for each??
bufferArr.appendByte(firstVal);
bufferArr.appendBytes(secondVal);
bufferArr.appendBuffer(anotherUint8Array);

【问题讨论】:

标签: javascript buffer arraybuffer typed-arrays


【解决方案1】:

Paul 的回答允许您将一个 TypedArray 连接到现有的 TypedArray。在 ES6 中,您可以使用以下函数来连接多个 TypedArray:

function concatenate(resultConstructor, ...arrays) {
    let totalLength = 0;
    for (const arr of arrays) {
        totalLength += arr.length;
    }
    const result = new resultConstructor(totalLength);
    let offset = 0;
    for (const arr of arrays) {
        result.set(arr, offset);
        offset += arr.length;
    }
    return result;
}

const ta = concatenate(Uint8Array,
    Uint8Array.of(1, 2), Uint8Array.of(3, 4));
console.log(ta); // Uint8Array [1, 2, 3, 4]
console.log(ta.buffer.byteLength); // 4

追加一个新字节是:

const byte = 3;
concatenate(Uint8Array, Uint8Array.of(1, 2), Uint8Array.of(byte));

这个方法可以在ExploringJS找到。

【讨论】:

    【解决方案2】:

    你可以用一个新的ArrayBuffer创建一个新的TypedArray,但是你不能改变一个现有缓冲区的大小

    function concatTypedArrays(a, b) { // a, b TypedArray of same type
        var c = new (a.constructor)(a.length + b.length);
        c.set(a, 0);
        c.set(b, a.length);
        return c;
    }
    

    现在可以做

    var a = new Uint8Array(2),
        b = new Uint8Array(3);
    a[0] = 1; a[1] = 2;
    b[0] = 3; b[1] = 4;
    concatTypedArrays(a, b); // [1, 2, 3, 4, 0] Uint8Array length 5
    

    如果你想使用不同的类型,请通过Uint8Array,因为最小单位是一个字节,即

    function concatBuffers(a, b) {
        return concatTypedArrays(
            new Uint8Array(a.buffer || a), 
            new Uint8Array(b.buffer || b)
        ).buffer;
    }
    

    这意味着.length 将按预期工作,您现在可以将其转换为您选择的类型化数组(但请确保它是一个可以接受缓冲区的.byteLength 的类型)


    从这里,您现在可以实现任何您喜欢的方法来连接数据,例如

    function concatBytes(ui8a, byte) {
        var b = new Uint8Array(1);
        b[0] = byte;
        return concatTypedArrays(ui8a, b);
    }
    
    var u8 = new Uint8Array(0);
    u8 = concatBytes(u8, 0x80); // [128]
    

    【讨论】:

    • 感谢@Paul S。将这些基本功能作为规范的一部分并在本地实现会很好,但您的解决方案非常好。一个问题我还有一个问题,你将如何附加一个多字节,让我们说一个 4 字节的值到一个 typedarray。我们可以为每个单个字节循环并多次调用您建议的 concatBytes 函数,但是可以以更好的方式完成吗?
    • @codneto 您的多字节是如何存储的?例如如果您使用整数,您如何知道0x3D7F0x00003D7F 之间的区别?是的,我同意应该有一些原生的 concat,但我认为不应该有原生的 pushlength 变化 - 这不是类型化数组的工作方式
    • S,我有一些函数返回 4 字节值,我需要将其添加到缓冲区。我还从流中读取一些字节并附加到缓冲区,有时基于一些标志我必须读取 1、2 或 4 个字节值,所有这些都需要附加到缓冲区。我应该如何完成将这些多字节值附加到缓冲区?
    • @codneto 把它写成一个循环。循环的最佳位置是为新数据创建一个n long Uint8Array,并在与之前的数据连接之前使用循环设置其值。
    • 根据您的建议,我将concatBytes 更改如下。我认为它会起作用。 function concatBytes(ui8a, bytes) { var b = new Uint8Array(bytes.length); bytes.forEach(function (byte, index) { b[index] = byte; });返回 concatTypedArrays(ui8a, b); } var u8 = 新的 Uint8Array(0); // 追加 0x80C83B u8 = concatBytes(u8, [0x80, 0xC8, 0x3B]); // 128, 200, 59]
    猜你喜欢
    • 2017-09-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-02-03
    • 1970-01-01
    • 2012-07-17
    • 1970-01-01
    相关资源
    最近更新 更多