Episode ini membedah file I/O modern dengan fs/promises dan stream untuk menangani file besar tanpa membebani memori. Kalian juga belajar pipeline untuk menyambung stream dan readline untuk memproses file baris per baris.

Di episode 3 kita membaca file dengan versi Sync yang memblokir thread utama. Untuk aplikasi server, itu bukan pilihan. Node.js menyediakan dua pendekatan yang tepat: API Promise dari fs/promises untuk operasi file biasa, dan stream untuk file besar atau data yang mengalir terus-menerus.
Episode 5 membahas keduanya. Kalian akan melihat fs/promises dengan async/await yang bersih, konsep stream yang hemat memori, pipeline untuk menyambung stream, serta readline untuk memproses file log baris per baris — pola yang sangat umum di dunia nyata.
Modul node:fs/promises menyediakan seluruh fungsi fs dalam bentuk Promise, tanpa akhiran Sync dan tanpa callback yang bersarang:
import { readFile, writeFile, mkdir } from "node:fs/promises";
await mkdir("data", { recursive: true });
await writeFile("data/catatan.txt", "Belajar stream");
const isi = await readFile("data/catatan.txt", "utf8");
console.log(isi);writeFile dan readFile mengembalikan Promise sehingga bisa dipakai dengan await. Karena ESM mendukung top-level await (episode 4), contoh di atas bisa berjalan langsung. Opsi recursive: true pada mkdir membuat folder tanpa error jika sudah ada.
Berbeda dengan callback yang memakai pola error-first, versi Promise memakai try/catch standar:
import { readFile } from "node:fs/promises";
try {
const isi = await readFile("tidak-ada.txt", "utf8");
console.log(isi);
} catch (err) {
console.error("Gagal membaca:", err.message);
}await readFile("tidak-ada.txt", "utf8") melempar error ENOENT ketika file tidak ditemukan, dan blok catch menangkapnya. Pola ini jauh lebih mudah dibaca daripada callback bersarang — detail lebih lanjut tentang error akan kita bahas di episode 6.
Membaca file 2 gigabyte dengan readFile akan menaruh seluruh isinya di memori — risiko OOM. Stream memecah masalah ini: data dibaca dalam potongan (chunk) kecil, diproses, lalu dilepas. Memori tetap rendah berapa pun ukuran file.
Stream di Node.js punya empat tipe:
createReadStream.createWriteStream.zlib.createGzip.pipeline dari node:stream/promises menyambungkan stream sekaligus menangani error dan penutupan dengan benar:
import { createReadStream, createWriteStream } from "node:fs";
import { pipeline } from "node:stream/promises";
await pipeline(
createReadStream("akses.log"),
createWriteStream("salinan.log"),
);
console.log("Selesai streaming");pipeline(createReadStream("akses.log"), createWriteStream("salinan.log")) mengalirkan data dari sumber ke tujuan dalam potongan kecil. Gunakan pipeline daripada metode .pipe() langsung — pipeline memastikan aliran dibersihkan dan error diteruskan dengan benar.
Untuk memproses setiap potongan di tengah aliran, sisipkan stream Transform:
import { createReadStream, createWriteStream } from "node:fs";
import { Transform } from "node:stream";
import { pipeline } from "node:stream/promises";
const uppercase = new Transform({
transform(chunk, enc, callback) {
callback(null, chunk.toString().toUpperCase());
},
});
await pipeline(
createReadStream("data.txt"),
uppercase,
createWriteStream("hasil.txt"),
);Objek Transform di atas mengubah setiap potongan menjadi huruf kapital sebelum diteruskan ke tujuan. Antara stream sumber dan tujuan bisa disisipkan banyak transform — inilah dasar dari pipeline kompresi, enkripsi, dan parsing log.
Ketika kalian perlu memproses file baris per baris — misalnya log atau CSV — node:readline adalah pilihan tepat:
import { createReadStream } from "node:fs";
import { createInterface } from "node:readline";
const rl = createInterface({
input: createReadStream("data.txt"),
});
for await (const baris of rl) {
console.log("Baris:", baris);
}createInterface({ input: createReadStream("data.txt") }) membungkus stream file menjadi antarmuka baris, dan loop for await memproses setiap baris satu per satu. Pola ini dipakai luas untuk agregasi log dan import data dalam jumlah besar.
Aturan memilih cukup sederhana:
readFile dari fs/promises.readline.Transform dalam pipeline.Di dunia nyata, server log, uploader file, dan media streaming hampir selalu memakai stream. Memahami kapan beralih dari readFile ke stream adalah salah satu pembeda antara kode pemula dan kode production.
Inti yang harus dibawa pulang:
fs/promises menyediakan file I/O dengan async/await yang bersih.pipeline menyambung stream sekaligus menangani error.Transform memodifikasi data di tengah aliran.readline memproses file baris per baris dengan loop for await.readFile; file besar dan data mengalir pakai stream.Di episode 6 selanjutnya kita akan membahas penanganan error dan debugging di Node — pola try/catch, error-first callback, event error, uncaught exception, serta debugging dengan inspector dan DevTools. Ini keterampilan yang menyelamatkan kalian setiap hari sebagai pengembang backend.