首页 文章

如何将二进制数据附加到node.js中的缓冲区

提问于
浏览 172
53

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

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

我想追加 0x03 .

如何附加更多二进制数据?我在文档中搜索但是为了追加数据它必须是一个字符串,如果没有,就会发生错误(TypeError:Argument必须是一个字符串):

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>

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

您是否知道添加二进制数据的更好方法?

EDIT

我写了一个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

LAST UPDATE

使用concat .

3 回答

  • 100

    缓冲区总是固定大小,没有内置的方法来动态调整它们的大小,因此将它复制到更大的缓冲区的方法是唯一的方法 .

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

  • 7

    这是为了帮助那些来到这里寻找需要纯粹方法的解决方案的人 . 我建议理解这个问题,因为它可能发生在许多不同的地方,而不仅仅是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;
    };
    
  • 4

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

    Node现在可以自己concatenate buffers .

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

    Node.js的旧答案~0.6

    我使用模块添加 .concat 函数,其中包括:

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

    我知道这不是一个“纯粹”的解决方案,但它对我的目的非常有效 .

相关问题