95

我有一个包含一些二进制数据的缓冲区:

var b = new Buffer ([0x00, 0x01, 0x02]);

我想追加0x03.

如何附加更多二进制数据?我在文档中搜索,但是对于附加数据,它必须是一个字符串,如果不是,则会发生错误(TypeError: Argument must be a string):

var b = new Buffer (256);
b.write ("hola");
console.log (b.toString ("utf8", 0, 4)); //hola
b.write (", adios", 4);
console.log (b.toString ("utf8", 0, 11)); //hola, adios

然后,我在这里看到的唯一解决方案是为每个附加的二进制数据创建一个新缓冲区,并将其复制到具有正确偏移量的主缓冲区:

var b = new Buffer (4); //4 for having a nice printed buffer, but the size will be 16KB
new Buffer ([0x00, 0x01, 0x02]).copy (b);
console.log (b); //<Buffer 00 01 02 00>
new Buffer ([0x03]).copy (b, 3);
console.log (b); //<Buffer 00 01 02 03>

但这似乎有点低效,因为我必须为每个追加实例化一个新缓冲区。

您知道附加二进制数据的更好方法吗?

编辑

我编写了一个BufferedWriter,它使用内部缓冲区将字节写入文件。与BufferedReader相同,但用于写入。

一个简单的例子:

//The BufferedWriter truncates the file because append == false
new BufferedWriter ("file")
    .on ("error", function (error){
        console.log (error);
    })

    //From the beginning of the file:
    .write ([0x00, 0x01, 0x02], 0, 3) //Writes 0x00, 0x01, 0x02
    .write (new Buffer ([0x03, 0x04]), 1, 1) //Writes 0x04
    .write (0x05) //Writes 0x05
    .close (); //Closes the writer. A flush is implicitly done.

//The BufferedWriter appends content to the end of the file because append == true
new BufferedWriter ("file", true)
    .on ("error", function (error){
        console.log (error);
    })

    //From the end of the file:
    .write (0xFF) //Writes 0xFF
    .close (); //Closes the writer. A flush is implicitly done.

//The file contains: 0x00, 0x01, 0x02, 0x04, 0x05, 0xFF

最后更新

使用连接

4

4 回答 4

161

更新了 Node.js 的答案 ~>0.8

Node 现在能够自行连接缓冲区

var newBuffer = Buffer.concat([buffer1, buffer2]);

Node.js 的旧答案 ~0.6

我使用一个模块来添加一个.concat功能,其中包括:

https://github.com/coolaj86/node-bufferjs

我知道这不是一个“纯粹的”解决方案,但它非常适合我的目的。

于 2012-04-27T18:47:05.027 回答
12

缓冲区始终具有固定大小,没有内置的方法可以动态调整它们的大小,因此将其复制到更大的缓冲区的方法是唯一的方法。

但是,为了提高效率,您可以使缓冲区大于原始内容,因此它包含一些“空闲”空间,您可以在其中添加数据而无需重新分配缓冲区。这样你就不需要创建一个新的 Buffer 并在每个追加操作中复制内容。

于 2012-04-27T18:41:06.870 回答
8

这是为了帮助任何来到这里寻找想要一种纯粹方法的解决方案的人。我建议理解这个问题,因为它可能发生在很多不同的地方,而不仅仅是 JS Buffer 对象。通过了解问题存在的原因以及如何解决它,您将提高您在未来解决其他问题的能力,因为这个问题非常重要。

对于我们这些必须用其他语言处理这些问题的人来说,设计一个解决方案是很自然的,但是有些人可能没有意识到如何抽象出复杂性并实现一个普遍有效的动态缓冲区。下面的代码可能有进一步优化的潜力。

我没有实现 read 方法以使示例保持较小的大小。

C(或任何处理内在分配的语言)中的realloc函数不保证在不移动现有数据的情况下扩展分配的大小 - 尽管有时是可能的。因此,当需要存储未知数量的数据时,大多数应用程序将使用如下方法而不是不断地重新分配,除非重新分配非常罕见。这本质上是大多数文件系统处理将数据写入文件的方式。文件系统只是分配另一个节点并将所有节点链接在一起,当您从中读取时,复杂性被抽象掉,因此文件/缓冲区似乎是一个连续的缓冲区。

对于那些希望了解仅仅提供高性能动态缓冲区的困难的人,您只需查看下面的代码,并研究内存堆算法以及内存堆如何为程序工作。

出于性能原因,大多数语言将提供固定大小的缓冲区,然后提供另一个大小动态的版本。一些语言系统选择了第三方系统,它们将核心功能保持在最低限度(核心分发),并鼓励开发人员创建库来解决附加或更高级别的问题。这就是为什么您可能会质疑为什么一种语言不提供某些功能。这个小的核心功能可以降低维护和增强语言的成本,但是您最终不得不编写自己的实现或依赖第三方。

var Buffer_A1 = function (chunk_size) {
    this.buffer_list = [];
    this.total_size = 0;
    this.cur_size = 0;
    this.cur_buffer = [];
    this.chunk_size = chunk_size || 4096;

    this.buffer_list.push(new Buffer(this.chunk_size));
};

Buffer_A1.prototype.writeByteArrayLimited = function (data, offset, length) {
    var can_write = length > (this.chunk_size - this.cur_size) ? (this.chunk_size - this.cur_size) : length;

    var lastbuf = this.buffer_list.length - 1;

    for (var x = 0; x < can_write; ++x) {
        this.buffer_list[lastbuf][this.cur_size + x] = data[x + offset];
    }

    this.cur_size += can_write;
    this.total_size += can_write;

    if (this.cur_size == this.chunk_size) {
        this.buffer_list.push(new Buffer(this.chunk_size));
        this.cur_size = 0;
    }

    return can_write;
};

/*
    The `data` parameter can be anything that is array like. It just must
    support indexing and a length and produce an acceptable value to be
    used with Buffer.
*/
Buffer_A1.prototype.writeByteArray = function (data, offset, length) {
    offset = offset == undefined ? 0 : offset;
    length = length == undefined ? data.length : length;

    var rem = length;
    while (rem > 0) {
        rem -= this.writeByteArrayLimited(data, length - rem, rem);
    }
};

Buffer_A1.prototype.readByteArray = function (data, offset, length) {
    /*
        If you really wanted to implement some read functionality
        then you would have to deal with unaligned reads which could
        span two buffers.
    */
};

Buffer_A1.prototype.getSingleBuffer = function () {
    var obuf = new Buffer(this.total_size);
    var cur_off = 0;
    var x;

    for (x = 0; x < this.buffer_list.length - 1; ++x) {
        this.buffer_list[x].copy(obuf, cur_off);
        cur_off += this.buffer_list[x].length;
    }

    this.buffer_list[x].copy(obuf, cur_off, 0, this.cur_size);

    return obuf;
};
于 2015-08-20T12:51:26.267 回答
0

将字节插入特定位置。

insertToArray(arr,index,item) {
   return Buffer.concat([arr.slice(0,index),Buffer.from(item,"utf-8"),arr.slice(index)]);
}
于 2020-03-31T11:38:12.503 回答