Mam bufor z danymi binarnymi:
var b = new Buffer ([0x00, 0x01, 0x02]);
i chcę dołączyć 0x03
.
Jak mogę dołączyć więcej danych binarnych? Szukam w dokumentacji, ale aby dołączyć dane, musi to być ciąg, jeśli nie, pojawia się błąd ( TypeError: Argument musi być stringiem ):
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
Wtedy jedynym rozwiązaniem, które widzę tutaj, jest utworzenie nowego bufora dla wszystkich dołączonych danych binarnych i skopiowanie go do głównego bufora z odpowiednim przesunięciem:
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>
Ale wydaje się to trochę nieefektywne, ponieważ muszę utworzyć wystąpienie nowego buforu dla każdego dodawania.
Czy znasz lepszy sposób na dołączanie danych binarnych?
EDYTOWAĆ
Napisałem BufferedWriter, który zapisuje bajty do pliku przy użyciu wewnętrznych buforów. To samo co BufferedReader, ale do pisania.
Szybki przykład:
//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
OSTATNIA AKTUALIZACJA
Użyj concat .
Odpowiedzi:
Zaktualizowana odpowiedź dla Node.js ~> 0.8
Węzeł może teraz samodzielnie łączyć bufory .
var newBuffer = Buffer.concat([buffer1, buffer2]);
Stara odpowiedź dla Node.js ~ 0.6
Korzystam z modułu do dodania
.concat
funkcji m.in .:https://github.com/coolaj86/node-bufferjs
Wiem, że nie jest to „czyste” rozwiązanie, ale do moich celów sprawdza się bardzo dobrze.
źródło
concat
Funkcja robi dokładnie to, co ja wysłana :( oblicza de łącznej długości a następnie kopiuje dane z wszystkich buforów Regulacja offsetu..Bufory mają zawsze stały rozmiar, nie ma możliwości dynamicznej zmiany ich rozmiaru, więc jedynym sposobem jest skopiowanie ich do większego bufora.
Jednak, aby być bardziej wydajnym, można zwiększyć rozmiar bufora niż oryginalna zawartość, aby zawierał trochę „wolnego” miejsca, do którego można dodawać dane bez ponownego przydzielania bufora. W ten sposób nie musisz tworzyć nowego bufora i kopiować zawartości przy każdej operacji dołączania.
źródło
Ma to pomóc każdemu, kto przyjeżdża tutaj i szuka rozwiązania, które pragnie czystego podejścia. Polecam zrozumienie tego problemu, ponieważ może się on zdarzyć w wielu różnych miejscach, nie tylko w przypadku obiektu JS Buffer. Dzięki zrozumieniu, dlaczego problem istnieje i jak go rozwiązać, poprawisz swoją zdolność rozwiązywania innych problemów w przyszłości, ponieważ ten jest tak fundamentalny.
Dla tych z nas, którzy mają do czynienia z tymi problemami w innych językach, znalezienie rozwiązania jest całkiem naturalne, ale są ludzie, którzy mogą nie zdawać sobie sprawy, jak odciąć się od złożoności i wdrożyć ogólnie skuteczny bufor dynamiczny. Poniższy kod może być dalej optymalizowany.
Pozostawiłem metodę odczytu niezaimplementowaną, aby przykład był niewielki.
realloc
Funkcja w C (lub dowolny język czynienia z nieodłącznych alokacji) nie gwarantuje, że alokacja zostanie poszerzona w rozmiarze z zewnątrz przeniesienie istniejących danych - choć czasem jest to możliwe. Dlatego większość aplikacji, które muszą przechowywać nieznaną ilość danych, będzie korzystać z metody podobnej do poniższej i nie będzie dokonywać ich ciągłej ponownej alokacji, chyba że ponowna alokacja jest bardzo rzadka. Zasadniczo jest to sposób, w jaki większość systemów plików obsługuje zapisywanie danych do pliku. System plików po prostu przydziela inny węzeł i utrzymuje wszystkie węzły połączone razem, a kiedy czytasz z niego, złożoność jest wyabstrahowana, tak że plik / bufor wydaje się być pojedynczym ciągłym buforem.Dla tych z Was, którzy chcą zrozumieć trudność związaną z zapewnieniem po prostu wysokowydajnego bufora dynamicznego, wystarczy przejrzeć poniższy kod, a także przeprowadzić badania nad algorytmami stosu pamięci i sposobem działania sterty pamięci dla programów.
Większość języków zapewnia bufor o stałym rozmiarze ze względu na wydajność, a następnie udostępnia inną wersję o dynamicznym rozmiarze. Niektóre systemy językowe wybierają system innej firmy, w którym podstawowe funkcje są minimalne (dystrybucja podstawowa) i zachęcają programistów do tworzenia bibliotek w celu rozwiązywania problemów dodatkowych lub wyższego poziomu. Dlatego możesz zapytać, dlaczego język nie zapewnia pewnych funkcji. Ta niewielka podstawowa funkcjonalność pozwala obniżyć koszty utrzymania i ulepszania języka, jednak ostatecznie musisz napisać własne implementacje lub polegać na stronie trzeciej.
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; };
źródło
this.buffer_list[lastbuf][this.cur_size + x] = data[x + offset];
, co niepotrzebnie wprowadza dodatkowe wyszukiwanie skrótu, wiele dodatkowych sprawdzeń tablicy i dwa sprawdzenia liczb całkowitych SMI z każdym bajtem. Jeśli oczekujesz wydajności, gorąco zachęcam, abyś nie korzystał z tej odpowiedzi. Zamiast tego przydziel nową tablicę o żądanym rozmiarze i skopiuj dane do nowej tablicy. To właśnie robi Java i jest naprawdę szybki.wstaw bajt w określone miejsce.
insertToArray(arr,index,item) { return Buffer.concat([arr.slice(0,index),Buffer.from(item,"utf-8"),arr.slice(index)]); }
źródło