31

我正在处理ArrayBuffer对象,我想复制它们。虽然这对于实际的指针和 来说相当容易memcpy,但我在 Javascript 中找不到任何直接的方法来做到这一点。

现在,这就是我复制我的方式ArrayBuffers

function copy(buffer)
{
    var bytes = new Uint8Array(buffer);
    var output = new ArrayBuffer(buffer.byteLength);
    var outputBytes = new Uint8Array(output);
    for (var i = 0; i < bytes.length; i++)
        outputBytes[i] = bytes[i];
    return output;
}

有没有更漂亮的方法?

4

8 回答 8

52

我更喜欢下面的方法

function copy(src)  {
    var dst = new ArrayBuffer(src.byteLength);
    new Uint8Array(dst).set(new Uint8Array(src));
    return dst;
}
于 2014-03-01T12:57:49.943 回答
33

看来,只需传入源数据视图即可执行副本:

var a = new Uint8Array([2,3,4,5]);
var b = new Uint8Array(a);
a[0] = 6;
console.log(a); // [6, 3, 4, 5]
console.log(b); // [2, 3, 4, 5]

在 FF 33 和 Chrome 36 中测试。

于 2014-08-12T03:35:24.443 回答
32

ArrayBuffer应该支持slice(http://www.khronos.org/registry/typedarray/specs/latest/)所以你可以试试,

buffer.slice(0);

它适用于 Chrome 18,但不适用于 Firefox 10 或 11。至于 Firefox,您需要手动复制它。slice()您可以在 Firefox中进行猴子补丁,因为 Chrome 的slice()性能会优于手动副本。这看起来像,

if (!ArrayBuffer.prototype.slice)
    ArrayBuffer.prototype.slice = function (start, end) {
        var that = new Uint8Array(this);
        if (end == undefined) end = that.length;
        var result = new ArrayBuffer(end - start);
        var resultArray = new Uint8Array(result);
        for (var i = 0; i < resultArray.length; i++)
           resultArray[i] = that[i + start];
        return result;
    }

然后你可以打电话,

buffer.slice(0);

在 Chrome 和 Firefox 中复制数组。

于 2012-04-11T06:49:27.843 回答
2

嗯...如果它是您要切片的 Uint8Array(从逻辑上讲,它应该是),这可能会起作用。

 if (!Uint8Array.prototype.slice && 'subarray' in Uint8Array.prototype)
     Uint8Array.prototype.slice = Uint8Array.prototype.subarray;
于 2013-06-06T10:41:16.850 回答
2

更快且稍微复杂的chuckj答案版本。应该在大型类型化数组上使用少约 8 倍的复制操作。基本上我们复制尽可能多的 8 字节块,然后复制剩余的 0-7 字节。这在当前版本的 IE 中特别有用,因为它没有为 ArrayBuffer 实现切片方法。

if (!ArrayBuffer.prototype.slice)
    ArrayBuffer.prototype.slice = function (start, end) {
    if (end == undefined) end = that.length;
    var length = end - start;
    var lengthDouble = Math.floor(length / Float64Array.BYTES_PER_ELEMENT); 
    // ArrayBuffer that will be returned
    var result = new ArrayBuffer(length);

    var that = new Float64Array(this, start, lengthDouble)
    var resultArray = new Float64Array(result, 0, lengthDouble);

    for (var i = 0; i < resultArray.length; i++)
       resultArray[i] = that[i];

    // copying over the remaining bytes
    that = new Uint8Array(this, start + lengthDouble * Float64Array.BYTES_PER_ELEMENT)
    resultArray = new Uint8Array(result, lengthDouble * Float64Array.BYTES_PER_ELEMENT);

    for (var i = 0; i < resultArray.length; i++)
       resultArray[i] = that[i];

    return result;
}
于 2014-01-30T20:03:40.370 回答
1

围绕. Buffer_ ArrayBuffer这是共享内存,不会复制。然后从 wrapping 创建一个新的 Buffer Buffer。这将复制数据。最后得到一个新的Buffer参考ArrayBuffer

这是我能找到的最直接的方法。最有效率?也许。

const wrappingBuffer = Buffer.from(arrayBuffer)
const copiedBuffer = Buffer.from(wrappingBuffer)
const copiedArrayBuffer = copiedBuffer.buffer
于 2022-02-15T12:08:06.363 回答
0

在某些情况下(例如 webaudio Audiobuffers),您只有对 2 个数组的引用。
因此,如果您将 array1 作为 float32Array 并将 array2 作为 float32Array,
则必须逐个元素地进行复制。

为此,您可以使用不同的方法。

            var ib=z.inputBuffer.getChannelData(0);
            var ob=z.outputBuffer.getChannelData(0);

            ib.forEach((chd,i)=>ob[i]=chd);

或者这个更好,可能更快

            ob.set(ib);

这是因为 Array.set 用多个数据填充现有数组(甚至来自另一个数组)

于 2019-09-06T16:56:52.207 回答
0

上面的一些操作只做“浅”的拷贝。在使用工人和可转移数组时,您需要进行深度复制。

function copyTypedArray(original, deep){
    var copy;
    var kon = original.constructor;
    if(deep){
        var len = original.length;
        copy = new kon(len);
        for (var k=len; --k;) {
            copy[k] = original[k];
        }
    } else {
        var sBuf = original.buffer;
        copy = new kon(sBuf);
        copy.set(original);
    }
    return copy;
}

提示(对于困惑的人):类型化数组包含一个 ArrayBuffer,可以通过“buffer”属性获得。

var arr = new Float32Array(8);
arr.buffer <-- this is an ArrayBuffer
于 2021-03-04T07:11:53.273 回答