Node.js Buffers

An Introduction to Buffers

A Buffer is an area in memory (typically RAM) that is used to store binary data. Binary is a collection or a set of 0 and 1. Each number in binary, or each 0 and 1 in a collection, is called a bit. Since JavaScript does not have a data type as 'byte' in its core API, so, to handle the binary data, Node.js includes a binary buffer application with a built-in module known as a buffer.

Buffer represents a fixed portion of memory (can't be altered) allocated outside of the JavaScript V8 engine. Buffers are very much similar to array in JavaScript, which stores a sequence of integers.  

Need for Buffers

To help the developers with binary data, buffers were introduced in an ecosystem that conventionally only allocated with strings rather than binaries. Buffers are deeply interconnected with the streams, which implies that when a stream processor accepts data faster than it can digest, it sends the data to a buffer.

To understand a Buffer's simple visualization, let's take an example. When we are streaming a video, and the red line goes beyond our visualization point, the video starts to buffer, which indicates that we are downloading data faster than we are viewing it. Thus, the browser starts to buffer it.

Creating a Buffer

There are three different methods allocated in Buffer API, which can create a new buffer, such as Buffer.from(), Buffer.alloc(), and Buffer.allocUnsafe().

We can create a void buffer with a size of 12 bytes.

const buf1 = Buffer.alloc(12);

We can also create a buffer from UTF-8 encoded strings:

const buf2 = Buffer.from(‘Hello!’);

There are various encodings accepted while creating a buffer. Some of them are given below:

  • ASCII
  • UTF-8
  • Base64
  • Latin1
  • Binary
  • Hex

The last method to create a buffer is given below:

const buf3 = Buffer.allocUnsafe(12);

However, this method might return the old data, which could be sensitive and must be overwritten.

Interacting with Buffers

Accessing the content of a Buffer

A Buffer is an array of bytes. Thus, it can be accessed as an array.

For Example:

const buf = Buffer.from('Hello!')
console.log(buf[0]);    // 72
console.log(buf[1]);    // 101
console.log(buf[2]);    // 108
console.log(buf[3]);    // 108
console.log(buf[4]);    // 111

The output numbers are the Unicode Codes that represents the character in the position of buffer. (Here, H => 72, e => 101, l => 108, and o => 111, respectively.)

We can also print the buffer's full content with the help of the toString() method. Here's an example is given below:

const buf = Buffer.from('Welcome to tutorialandexample.com');




console.log(buf.toString());

The Output of the above snippet of code should look as follows:

Welcome to tutorialandexample.com

Note: A buffer will return random data containing the access to pre-initialized memory, not an empty buffer when initialized with a number that sets its size.

Getting the length of a Buffer

To check the length of a buffer, we can use the length property:

const buf = Buffer.from('Hello World!');
console.log(buf.length)

The Output of the above snippet of code should look as follows:

12

Iterating over the contents of a Buffer

We can iterate over the instances of the buffer using the for loop:

const buf = Buffer.from('Hello World!');
for(const a of buf) {
    console.log(a);
};

The Output of the above snippet of code should look as follows:

72 
101
108
108
111
32 
87 
111
114
108
100
33

Changing the content of a Buffer

Buffer allows the users to write a whole string of data using the write() method.

const buf = Buffer.alloc(12);
buf.write('Hello World!');




console.log(buf.toString());

The Output of the above snippet of code should look as follows:

Hello World!

Moreover, the buffer also allows the users to change the array syntax of a buffer. It is much similar to the method that we used to access the content of a buffer.

const buf = Buffer.from('Hello World!');
buf[2] = 111;
buf[9] = 120;




console.log(buf.toString());

The Output of the above snippet of code should look as follows:

Heolo Worxd!

Copying a Buffer

We can copy a buffer using the copy() method:

const buf1 = Buffer.from('Hello World!');
let buf2 = Buffer.alloc(12); // Allocating 12 bytes
buf1.copy(buf2);




console.log(buf2.toString());

The Output of the above snippet of code should look as follows:

Hello World!

We can copy the whole buffer as the default setting. However, three parameters can be used in order to define the starting position, the ending position and the new buffer length:

const buf1 = Buffer.from('Hello World!');
let buf2 = Buffer.alloc(5); // Allocating 5 bytes
buf1.copy(buf2, 0, 0, 5);




console.log(buf2.toString());

The Output of the above snippet of code will look as follows:

Hello

Slicing a Buffer

We can create a slice if we want to create a partial visualization of a buffer. It is a point to understand that a slice is not a copy, which implies that the original buffer is still the truth source. If any changes are made to the original buffer, it will also be visible in the slice.

We can use the slice() method to create a slice. The parameters will be the starting position and the ending position:

const buf = Buffer.from('Hello!');
buf.slice(0).toString();
const slice = buf.slice(0, 3);
console.log(slice.toString());
buf[2] = 120;
console.log(slice.toString());

The Output of the above snippet of code should look as follows:

Hel
Hex