Files and paths
Reading files with Node
Learn how to read files in Node.js with the fs module, using the asynchronous readFile() and synchronous readFileSync(), and why streams suit big files.
The simplest way to read a file in Node is fs.readFile(). Pass the file path and a callback that receives the data (and any error):
const fs = require('fs')
fs.readFile('/Users/flavio/test.txt', (err, data) => {
if (err) {
console.error(err)
return
}
console.log(data)
})
Run this and the output might surprise you. Instead of the file text you get raw bytes:
<Buffer 48 65 6c 6c 6f>
There is no default string encoding. If you do not specify one, Node hands you a Buffer object. Pass the encoding as the second parameter, before the callback, to get a string:
fs.readFile('/Users/flavio/test.txt', 'utf8', (err, data) => {
if (err) {
console.error(err)
return
}
console.log(data) //Hello
})
Alternatively, use the synchronous version fs.readFileSync():
const fs = require('fs')
try {
const data = fs.readFileSync('/Users/flavio/test.txt', 'utf8')
console.log(data)
} catch (err) {
console.error(err)
}
The trade-off is right in the name. readFileSync() blocks the entire process until the file is read. In a small command-line script that is fine, and the code is easier to follow. In a server, it freezes every other request while the disk works. Use the asynchronous versions there.
There is also a promise-based API in fs/promises, which pairs nicely with await:
const fs = require('fs/promises')
async function main() {
const data = await fs.readFile('/Users/flavio/test.txt', 'utf8')
console.log(data)
}
main()
When the file is missing
The most common failure is a wrong path. You get:
Error: ENOENT: no such file or directory, open '/Users/flavio/test.txt'
ENOENT means the file does not exist at that path. Check err.code === 'ENOENT' when a missing file is an expected case you want to handle gracefully, instead of treating every error the same way.
Big files
Both fs.readFile() and fs.readFileSync() read the full content of the file in memory before returning the data.
That means big files hit your memory hard. A 2 GB log file means 2 GB of RAM just to look at it.
In that case, use streams: fs.createReadStream() gives you the file in small chunks, so memory use stays flat no matter how large the file is.
Lesson completed