Trabalhando com Arquivos em JavaScript (Node.js): Um Guia Detalhado
What is it and why? (a real-life analogy)
Imagine you are the captain of a spaceship. You have a logbook where you record everything that happens during the flight: coordinates, fuel levels, encounters with asteroids. When the flight is over, you can open this logbook and remember every detail of the journey. Your computer is like that ship, and the files on the hard drive are an endless number of logbooks.
When a program runs, all its data lives in RAM — like thoughts in a captain's head. But as soon as you turn off the computer, these thoughts disappear forever. Files, however, allow you to save information for years: texts, settings, calculation results, user lists. In JavaScript (Node.js), we can not only read these "logbooks" but also create new ones, add to them, and even delete them.
💡 Important to understand: In the browser, JavaScript does not have access to the computer's file system — this is done for security reasons. But Node.js, which runs on the server, gives the programmer full control over files. This is exactly what we will be studying.
Reading files is like opening a book. You can read it entirely (all at once), you can read it line by line (like a poem), or even in pieces (like an encyclopedia where you only need one article). In this article, we will learn all these methods.
Theory: how it works internally
To understand how Node.js works with files, you need to understand three key concepts: streams, buffers, and encodings.
Streams
Imagine you are drinking juice through a straw. You don't drink the whole glass in one gulp — you draw the liquid in gradually. A stream in programming works the same way: data is transferred in small portions. This is especially important for large files (videos, databases), because loading them entirely into memory is like trying to swallow a whole watermelon.
In Node.js, there are four types of streams:
- Readable — a stream for reading (you draw in the juice)
- Writable — a stream for writing (you pour out the juice)
- Duplex — you can both read and write (like a sink with two faucets)
- Transform — data can be modified on the fly (like a water filter)
Buffers
A buffer is a temporary storage where pieces of data are placed while you decide what to do with them. When you read a file through a stream, the data doesn't come as strings, but as sets of bytes. The buffer allows you to collect these bytes and turn them into text or another format.
Imagine you are assembling a puzzle: you don't put each piece in its place right away, but first you put them in a pile (buffer), and then you assemble the picture.
Encodings
The computer stores everything as numbers (bytes). To turn these numbers into letters, you need a mapping table — an encoding. The most popular one is UTF-8, which understands Russian letters, hieroglyphs, and emojis. If you open a file with the wrong encoding, you will see "gibberish" — meaningless symbols.
⚠️ Golden rule: Always specify the 'utf-8' encoding when working with text files. Otherwise, Node.js will return raw bytes to you, which are inconvenient to work with.
Synchronous and asynchronous approach
Node.js is famous for its asynchronicity. It's like ordering in a restaurant: you can sit and wait for the chef to cook the food (synchronously), or you can do your own thing, and when the dish is ready, the waiter will call you (asynchronously).
When reading files, you have a choice:
- Synchronous methods (with the Sync suffix) — the program stops and waits until the file is read. Simple, but slow.
- Asynchronous methods with callbacks — you say: "Read the file and, when you're done, do this." Old style.
- Asynchronous methods with promises — a modern approach. You use async/await, and the code looks almost synchronous, but doesn't block the program.
Syntax in JavaScript (Node.js): all forms and options
To work with files in Node.js, the built-in fs (file system) module is used. To include it, you need to write at the beginning of the program:
const fs = require('fs'); // Old way (CommonJS)
// or
import fs from 'fs'; // New way (ES Modules) — if "type": "module" is set in package.json
Let's look at all the main methods for reading files. I've grouped them in a table for clarity.
Table of file reading methods
| Method | Type | What it does | When to use |
|---|---|---|---|
fs.readFileSync() |
Synchronous | Reads the entire file into memory at once | For small files in simple scripts |
fs.readFile() |
Asynchronous (callback) | Reads the entire file, calls a function when ready | When you need to read a file without stopping the program |
fs.promises.readFile() |
Asynchronous (promise) | Same thing, but returns a Promise | Modern standard, convenient with async/await |
fs.createReadStream() |
Stream-based | Reads the file in pieces (chunks) | For large files (videos, logs, databases) |