JavaScript

Read and write files byte by byte

Another way to access a file is fs.open() function. Once a file is accessed, you can read data from it using fs.read() function or write data to it using fs.write() function.

The fs.write() and fs.read() functions use buffer for reading from or writing to a file.

Open a file for reading or writing using fs.open method

Syntax: fs.open(path, flags [,mode], callback)

The parameters for fs.open() are:

  • path
    Filename and path e.g. D:\BrainBell\map.xml
  • flags
    • r Opens the file for reading
    • r+ Opens the file for reading and writing
    • w Opens the file for writing
    • wx Opens the file for writing, but fails if the file does exist
    • w+ Opens the file for reading and writing
    • wx+ Opens the file for reading and writing, but fails if the file exists
    • a Opens the file for appending
    • ax Opens the file for appending, fails if the file exists
    • a+ Opens the file for reading and appending
    • ax+ Opens the file for reading and appending, but fails if the file exists
  • mode
    An optional value that sets the sticky and permission bits on the file if created, and defaults to 0666.
  • Callback function
    The callback function has two parameters:
    1. error If an error occurs
    2. fd A file descriptor, used by subsequent file operations.

The following example shows how to open a file for reading:

//Open a file for reading
const file = './file.txt',
fs = require('fs');

fs.open(file,'r', (err,fd) => {
 if (err){
  console.log(err);
 }
 else {
  /*...*/
 }
}

To open a file for writing, just change the flag parameter r to w, for example:

//Open a file for writing
const file = './file.txt',
fs = require('fs');

fs.open(file,'w', (err,fd) => {
 if (err){
  console.log(err);
 }
 else {
  /*...*/
 }
}

What is a file descriptor

A file descriptor is a handle used to access a file. It is a non-negative integer uniquely referencing a specific file.

//Print fd
const file = './file.txt',
fs = require('fs');

fs.open(file,'w', (err,fd) => {
 if (err){
  console.log(err);
 }
 else {
  console.log(fd);//3
 }
}

The above example prints fd value, a number, on the screen.

fs.read() and fs.write()

Next, we’ll explore how to read the content from an opened file or write content to the opened file.

The fs.read() and fs.write() functions share the same parameters:

  • fd
    The fs.open() method’s callback file descriptor
  • buffer
    The buffer used to either hold data to be written or appended, or read
  • offset
    The offset where the input/output (I/O) operation begins in the buffer
  • length
    The number of bytes to read or write in the buffer
  • position
    Position in the file where to begin reading or writing.
  • callback
    The callback functions have three arguments:
    1. err
      An error, if operation failed
    2. bytes
      Bytes read (or written)
    3. buffer
      The buffer.
//fs.read syntax with callback
fs.read(
 fd, buffer, offset, length, position, 
  (err, bytes, buffer) => {
})

//fs.write syntax
fs.write(
 fd, buffer, offset, length, position, 
  (err, bytes, buffer) => {
})

Reading file content using fs.read method

Syntax: fs.read(fd, buffer, offset, length, position, callback)

Files are composed of ordered bytes, and these bytes are addressable by their position. Once we have a file descriptor fd, we can begin to read length number of bytes and insert those into buffer, insertion beginning at a given buffer offset.

How it all works? Let’s create an app that read a file and print it to the console. I’ve created a file file.txt which contains 26 English alphabets letters:

//file.txt
abcdefghijklmnopqrstuvwxyz

The following code will read the content of file.txt and print it to the console:

//readFile.js

const fs = require('fs'),
len = 26,
buff = Buffer.alloc(len),
pos = 0, offset =0,
file = './file.txt';

fs.open(file, 'r', (err, fd) => {
 fs.read(fd, buff, offset, len, pos,
 (err, bytes, buff) => { 
  console.log(buff.toString());
 });
});

The Buffer.alloc(len) creates a new Buffer object and allocates it 26 bytes size which is the size of our file. I’ve received the following output:

D:\BrainBell>node readFile.js
abcdefghijklmnopqrstuvwxyz

Change the len value from 26 to 20 and execute the code again:

D:\BrainBell>node readFile.js
abcdefghijklmnopqrst

Change the pos value from 0 to 6:

D:\BrainBell>node readFile.js
ghijklmnopqrstuvwxyz

Writing content to a file using fs.write method

Syntax: fs.write(fd, buffer, offset, length, position, callback)

The following example demonstrates how to open a file for writing, file will created if if not already exist:

const fs = require('fs'),
file = './file.txt';

fs.open(file, 'w+', (err, fd) => {
 let buf = Buffer.from('write this line');
});

We created a new Buffer object containing our text to write to file. We’ll read the file after writing the text and print the output to the console:

fs.open(file, 'w+', (err, fd) => {
 let buf = Buffer.from('write this line'),
 pos = 0,offset = 0,
 len = buf.length;

 fs.write(fd, buf, offset, len, pos,
 (err,bytes,buff) => {

  let buf2 = Buffer.alloc(len);
  fs.read(fd,buf2,offset, len, pos,
  (err,bytes,buff2) => {
   console.log(buff2.toString());

  });
 });
});

Note: I’ve skipped the error checking for the code clarity.

In above code, we open a file for reading and writing, then we created a new Buffer object containing our text using Buffer.from method and write it to the file. Then we read the file's content and prints the output on the console.