【问题标题】:How to append binary data to a buffer in node.js如何将二进制数据附加到 node.js 中的缓冲区
【发布时间】:2012-05-08 12:14:33
【问题描述】:

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

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

最后更新

使用concat

【问题讨论】:

  • 如果顶部的迷你答案是实际答案并且问题在这里是独立的,那么阅读起来会更清楚。

标签: node.js binary append buffer


【解决方案1】:

Node.js 的更新答案 ~>0.8

节点现在可以自己concatenate buffers

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

Node.js 的旧答案 ~0.6

我使用一个模块来添加一个.concat 函数,等等:

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

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

【讨论】:

  • concat 函数完全符合我发布的内容:(。它计算总长度,然后复制调整偏移量的所有缓冲区的数据。
  • 这就是它的工作方式。正如@stewe 指出的那样,由于分配内存的方式,缓冲区被实例化为固定大小。
  • 但是在 c 中我们有 realloc 函数可以在必要时动态扩展内存。 node.js 应该知道这一点。
  • @GabrielLlamas,我建议向他们的存储库提交补丁。
  • 我找到了为什么 node.js 没有动态缓冲区:markmail.org/message/vx2h3uslwgludu3y
【解决方案2】:

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

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

【讨论】:

    【解决方案3】:

    这是为了帮助任何来到这里寻求纯粹方法的解决方案的人。我建议理解这个问题,因为它可能发生在很多不同的地方,而不仅仅是 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;
    };
    

    【讨论】:

    • 我建议在使用此解决方案时要格外小心。如果您想要可调整大小的缓冲区的原因是性能,不要使用它。写入可调整大小数组的每个字节都会引发this.buffer_list[lastbuf][this.cur_size + x] = data[x + offset];,这不必要地引入了额外的哈希查找、大量额外的数组检查以及每个字节的两次 SMI 整数检查。如果性能是您想要的,我强烈建议您不要使用此答案。相反,分配一个所需大小的新数组并将数据复制到新数组中。这就是 Java 所做的,而且速度非常快。
    【解决方案4】:

    将字节插入特定位置。

    insertToArray(arr,index,item) {
       return Buffer.concat([arr.slice(0,index),Buffer.from(item,"utf-8"),arr.slice(index)]);
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-12-28
      • 2020-05-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-09-06
      • 2019-11-24
      • 2015-08-10
      相关资源
      最近更新 更多