Node.js - File System

Welcome, future programmers! Today, we're diving into the exciting world of Node.js and its File System module. As your friendly neighborhood computer teacher, I'm here to guide you through this journey with plenty of examples and explanations. So, buckle up and let's get started!

Node.js - File System

Synchronous vs Asynchronous

Before we jump into the nitty-gritty of file operations, let's talk about two important concepts: synchronous and asynchronous operations.

Imagine you're at a coffee shop. In a synchronous world, you'd order your coffee, wait for it to be made, and then move on to the next task. In an asynchronous world, you'd order your coffee and then go about your business while the barista prepares it.

In Node.js, we have both synchronous and asynchronous methods for file operations. Let's look at an example:

const fs = require('fs');

// Synchronous read
const data = fs.readFileSync('hello.txt', 'utf8');
console.log(data);

// Asynchronous read
fs.readFile('hello.txt', 'utf8', (err, data) => {
  if (err) throw err;
  console.log(data);
});

In the synchronous version, our program waits until the file is read before moving on. In the asynchronous version, it continues executing while the file is being read, and then runs a callback function when it's done.

Writing a file

Now, let's learn how to write to a file. It's like leaving a note for your future self!

const fs = require('fs');

// Synchronous write
fs.writeFileSync('note.txt', 'Hello, Future Me!');

// Asynchronous write
fs.writeFile('note.txt', 'Hello, Future Me!', (err) => {
  if (err) throw err;
  console.log('File saved!');
});

In both cases, we're creating (or overwriting) a file called 'note.txt' with the content "Hello, Future Me!". The asynchronous version includes a callback function that runs after the file is written.

Reading a file

Reading a file is like opening that note you left for yourself. Let's see how it's done:

const fs = require('fs');

// Synchronous read
const data = fs.readFileSync('note.txt', 'utf8');
console.log(data);

// Asynchronous read
fs.readFile('note.txt', 'utf8', (err, data) => {
  if (err) throw err;
  console.log(data);
});

Both methods will output the contents of 'note.txt'. The 'utf8' parameter specifies the encoding of the file.

Open a file

Sometimes, we want more control over how we interact with a file. That's where the open method comes in:

const fs = require('fs');

// Asynchronous open
fs.open('myfile.txt', 'r', (err, fd) => {
  if (err) throw err;
  console.log('File opened successfully!');
  // Remember to close the file when you're done
  fs.close(fd, (err) => {
    if (err) throw err;
  });
});

This opens 'myfile.txt' in read mode ('r'). The fd in the callback is a file descriptor, which we'll use for further operations on the file.

Promises API

For those who prefer working with Promises (don't worry if you don't know what these are yet!), Node.js provides a Promise-based API for file operations:

const fs = require('fs').promises;

async function readMyFile() {
  try {
    const data = await fs.readFile('myfile.txt', 'utf8');
    console.log(data);
  } catch (error) {
    console.error('Error reading file:', error);
  }
}

readMyFile();

This achieves the same result as our earlier asynchronous readFile example, but using modern JavaScript syntax.

Get File Information

Curious about a file's stats? Node.js has got you covered:

const fs = require('fs');

fs.stat('myfile.txt', (err, stats) => {
  if (err) throw err;
  console.log(`File size: ${stats.size} bytes`);
  console.log(`Is it a directory? ${stats.isDirectory()}`);
  console.log(`Is it a file? ${stats.isFile()}`);
});

This gives us information like the file size, whether it's a directory or a file, and more.

Closing a File

Remember to always close your files when you're done with them. It's like putting the cap back on your toothpaste!

const fs = require('fs');

fs.open('myfile.txt', 'r', (err, fd) => {
  if (err) throw err;
  // Do some operations...
  fs.close(fd, (err) => {
    if (err) throw err;
    console.log('File closed successfully');
  });
});

Truncate a File

Sometimes you want to keep a file but remove its contents. That's where truncate comes in:

const fs = require('fs');

fs.truncate('myfile.txt', 0, (err) => {
  if (err) throw err;
  console.log('File content cleared!');
});

This reduces the file to 0 bytes, effectively clearing its contents.

Delete a File

When you're done with a file completely, you can delete it:

const fs = require('fs');

fs.unlink('myfile.txt', (err) => {
  if (err) throw err;
  console.log('File deleted successfully');
});

Just be careful with this one - there's no undo button in real life!

Create a Directory

Need a new folder? Here's how you make one:

const fs = require('fs');

fs.mkdir('mynewfolder', (err) => {
  if (err) throw err;
  console.log('Directory created successfully!');
});

Read a Directory

Want to see what's in a directory? Here's how:

const fs = require('fs');

fs.readdir('.', (err, files) => {
  if (err) throw err;
  console.log('Directory contents:');
  files.forEach(file => {
    console.log(file);
  });
});

This lists all files and subdirectories in the current directory.

Remove a Directory

And finally, if you want to remove a directory:

const fs = require('fs');

fs.rmdir('mynewfolder', (err) => {
  if (err) throw err;
  console.log('Directory removed successfully');
});

Note that this only works on empty directories.

Methods Reference

Here's a handy table of the methods we've covered:

Method Description
readFile Reads the entire contents of a file
writeFile Writes data to a file, replacing the file if it already exists
open Opens a file for reading or writing
close Closes a file descriptor
stat Gets information about a file
truncate Truncates a file to a specified length
unlink Deletes a file
mkdir Creates a new directory
readdir Reads the contents of a directory
rmdir Removes a directory

And there you have it! You're now equipped with the basics of file system operations in Node.js. Remember, practice makes perfect, so don't be afraid to experiment with these methods. Happy coding!

Credits: Image by storyset