Cách nối dữ liệu nhị phân vào bộ đệm trong node.js


81

Tôi có một bộ đệm với một số dữ liệu nhị phân:

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

và tôi muốn nối thêm 0x03.

Làm cách nào để nối thêm dữ liệu nhị phân? Tôi đang tìm kiếm trong tài liệu nhưng đối với dữ liệu thêm vào, nó phải là một chuỗi, nếu không, sẽ xảy ra lỗi ( TypeError: Argument phải là một chuỗi ):

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

Sau đó, giải pháp duy nhất tôi có thể thấy ở đây là tạo một bộ đệm mới cho mọi dữ liệu nhị phân được thêm vào và sao chép nó vào bộ đệm chính với độ lệch chính xác:

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>

Nhưng điều này có vẻ hơi không hiệu quả bởi vì tôi phải tạo một bộ đệm mới cho mỗi phần phụ.

Bạn có biết cách tốt hơn để bổ sung dữ liệu nhị phân không?

BIÊN TẬP

Tôi đã viết một BufferedWriter ghi các byte vào một tệp bằng bộ đệm nội bộ. Giống như BufferedReader nhưng để viết.

Một ví dụ nhanh:

//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

CẬP NHẬT CUỐI CÙNG

Sử dụng concat .


3
Sẽ rõ ràng hơn khi đọc nếu các câu trả lời nhỏ ở trên cùng là câu trả lời thực tế và câu hỏi nằm ở đây.
Anko

Câu trả lời:


139

Câu trả lời được cập nhật cho Node.js ~> 0.8

Node hiện có thể tự ghép các bộ đệm .

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

Câu trả lời cũ cho Node.js ~ 0,6

Tôi sử dụng một mô-đun để thêm một .concatchức năng, trong số những người khác:

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

Tôi biết nó không phải là một giải pháp "thuần túy", nhưng nó hoạt động rất tốt cho mục đích của tôi.


Các concatchức năng thực hiện chính xác những gì tôi đã đăng :( nó tính toán de tổng chiều dài và sau đó sao chép dữ liệu của tất cả các bộ đệm điều chỉnh bù đắp..
Gabriel Llamas

Đó là cách nó phải hoạt động. Như @stewe đã chỉ ra, Bộ đệm được khởi tạo với kích thước cố định, do cách cấp phát bộ nhớ.
Brad

2
Nhưng trong c chúng ta có hàm realloc để mở rộng bộ nhớ động khi cần thiết. Node.js nên biết điều này.
Gabriel Llamas

1
@GabrielLlamas, tôi khuyên bạn nên gửi bản vá cho kho lưu trữ của họ.
Brad

11
Tôi đã tìm thấy lý do tại sao node.js không có bộ đệm động: markmail.org/message/vx2h3uslwgludu3y
Gabriel Llamas

10

Bộ đệm luôn có kích thước cố định, không có cách nào được xây dựng để thay đổi kích thước động, vì vậy cách tiếp cận của bạn là sao chép nó vào Bộ đệm lớn hơn là cách duy nhất.

Tuy nhiên, để hiệu quả hơn, bạn có thể làm cho Bộ đệm lớn hơn nội dung ban đầu, vì vậy nó chứa một số không gian "trống" để bạn có thể thêm dữ liệu mà không cần phân bổ lại Bộ đệm. Bằng cách đó, bạn không cần tạo Bộ đệm mới và sao chép nội dung trên mỗi thao tác nối thêm.


8

Điều này là để giúp bất kỳ ai đến đây tìm kiếm một giải pháp muốn có một cách tiếp cận thuần túy. Tôi khuyên bạn nên hiểu vấn đề này vì nó có thể xảy ra ở rất nhiều nơi khác nhau không chỉ với một đối tượng Bộ đệm JS. Bằng cách hiểu tại sao vấn đề tồn tại và cách giải quyết nó, bạn sẽ cải thiện khả năng giải quyết các vấn đề khác trong tương lai vì vấn đề này rất cơ bản.

Đối với những người trong chúng ta phải đối phó với những vấn đề này bằng các ngôn ngữ khác, việc tìm ra giải pháp là điều hoàn toàn tự nhiên, nhưng có những người có thể không nhận ra cách làm thế nào để loại bỏ sự phức tạp và triển khai một bộ đệm động nói chung hiệu quả. Đoạn mã dưới đây có thể được tối ưu hóa hơn nữa.

Tôi đã không thực hiện phương pháp đọc để giữ cho ví dụ có kích thước nhỏ.

Các reallochàm trong C (hoặc bất kỳ giao dịch ngôn ngữ với phân bổ nội tại) không đảm bảo rằng việc phân bổ sẽ được mở rộng về quy mô với hiện di chuyển các dữ liệu hiện có - mặc dù đôi khi nó là có thể. Do đó hầu hết các ứng dụng khi cần lưu trữ một lượng dữ liệu không xác định sẽ sử dụng phương pháp như bên dưới và không phân bổ lại liên tục, trừ khi việc phân bổ lại rất ít thường xuyên. Về cơ bản đây là cách hầu hết các hệ thống tệp xử lý việc ghi dữ liệu vào tệp. Hệ thống tệp chỉ cần phân bổ một nút khác và giữ tất cả các nút được liên kết với nhau, và khi bạn đọc từ đó, độ phức tạp sẽ được trừu tượng hóa để tệp / bộ đệm dường như là một bộ đệm liền kề.

Đối với những người bạn muốn hiểu được khó khăn trong việc chỉ đơn giản cung cấp một bộ đệm động hiệu suất cao, bạn chỉ cần xem đoạn mã bên dưới, đồng thời thực hiện một số nghiên cứu về thuật toán heap bộ nhớ và cách heap bộ nhớ hoạt động cho các chương trình.

Hầu hết các ngôn ngữ sẽ cung cấp bộ đệm có kích thước cố định vì lý do hiệu suất, sau đó cung cấp một phiên bản khác có kích thước động. Một số hệ thống ngôn ngữ chọn hệ thống của bên thứ ba, nơi họ giữ chức năng cốt lõi ở mức tối thiểu (phân phối cốt lõi) và khuyến khích các nhà phát triển tạo thư viện để giải quyết các vấn đề bổ sung hoặc cấp cao hơn. Đây là lý do tại sao bạn có thể đặt câu hỏi tại sao một ngôn ngữ không cung cấp một số chức năng. Chức năng cốt lõi nhỏ này cho phép giảm chi phí trong việc duy trì và nâng cao ngôn ngữ, tuy nhiên bạn sẽ phải viết các triển khai của riêng mình hoặc phụ thuộc vào bên thứ ba.

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;
};

Tôi sẽ khuyên bạn nên hết sức thận trọng khi sử dụng giải pháp này. Nếu lý do bạn muốn bộ đệm có thể thay đổi kích thước là hiệu suất, không sử dụng điều này . Mỗi byte đơn được ghi vào mảng có thể thay đổi kích thước phải chịu this.buffer_list[lastbuf][this.cur_size + x] = data[x + offset];, điều này không cần thiết phải giới thiệu thêm một tra cứu băm, nhiều lần kiểm tra mảng bổ sung và hai lần kiểm tra số nguyên SMI với mỗi byte đơn. Nếu hiệu suất là những gì bạn muốn, tôi thực sự khuyên bạn không nên sử dụng câu trả lời này. Thay vào đó, hãy phân bổ một mảng mới có kích thước mong muốn và sao chép dữ liệu vào mảng mới. Đó là những gì Java làm và nó thực sự nhanh.
Jack Giffin

0

chèn byte vào vị trí cụ thể.

insertToArray(arr,index,item) {
   return Buffer.concat([arr.slice(0,index),Buffer.from(item,"utf-8"),arr.slice(index)]);
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.