Modul fs adalah antarmuka Node untuk sistem berkas. Modul ini menyediakan tiga ragam API yang berbagi nama fungsi tetapi berbeda mekanisme eksekusi: API sinkron memblokir event loop sampai selesai, API asinkron berbasis callback memanggil fungsi penerima ketika operasi selesai, dan API berbasis promise pada modul node:fs/promises mengembalikan promise yang dapat dipakai dengan await. Setelah membaca topik ini, pembaca dapat memilih ragam yang tepat, menulis berkas, membaca berkas, serta memeriksa metadata berkas.
Tiga ragam API#
API sinkron diidentifikasi oleh akhiran Sync pada nama fungsi, misalnya readFileSync dan writeFileSync. Fungsi ini memblokir thread utama selama operasi berlangsung sehingga tidak ada permintaan atau timer lain yang dapat diproses. API sinkron tepat dipakai pada skrip pendek satu kali seperti skrip inisialisasi atau pada bagian startup aplikasi sebelum server menerima permintaan. Pemakaian API sinkron di dalam penangan permintaan HTTP menurunkan throughput secara signifikan karena satu berkas yang dibaca memblokir seluruh antrean.
API asinkron berbasis callback memanggil fungsi penerima pada argumen terakhir. Konvensi Node menempatkan objek error sebagai argumen pertama fungsi penerima, pola yang dikenal sebagai error-first callback. Pola ini sudah ada sejak Node versi awal dan banyak dijumpai pada kode lama. Pada kode baru, API berbasis promise dari node:fs/promises lebih disukai karena menyederhanakan penanganan error lewat try/catch dan menyusun operasi berurutan tanpa bersarang.
const fs = require('node:fs');
fs.writeFileSync('catatan-sync.txt', 'baris satu\nbaris dua\n');
const data = fs.readFileSync('catatan-sync.txt', 'utf8');
console.log('isi:', JSON.stringify(data));
const stat = fs.statSync('catatan-sync.txt');
console.log('ukuran byte:', stat.size);
console.log('tipe:', stat.isFile() ? 'berkas' : 'dir');isi: "baris satu\nbaris dua\n"
ukuran byte: 21
tipe: berkasAPI sinkron di atas menulis berkas, membaca kembali isinya, dan mengambil metadata lewat statSync. Objek stats yang dikembalikan memiliki properti size dalam byte serta metode isFile dan isDirectory untuk membedakan jenis entri pada sistem berkas. Karena operasi berjalan sinkron, urutan pemanggilan langsung tercermin pada keluaran tanpa penanganan khusus.
API berbasis callback#
API asinkron berbasis callback menjalankan operasi tanpa memblokir thread. Fungsi penerima dipanggil setelah operasi selesai, dan argumen pertamanya berisi error bila terjadi kegagalan. Pola ini memaksa penulisan kode bersarang ketika beberapa operasi harus berurutan, yang dikenal sebagai callback hell. Untuk urutan yang panjang, transisi ke promise atau async/await menjadikan kode lebih datar dan lebih mudah dibaca.
const fs = require('node:fs');
fs.writeFile('catatan-cb.txt', 'data dari callback\n', (err) => {
if (err) {
console.error('error tulis:', err.message);
return;
}
fs.readFile('catatan-cb.txt', 'utf8', (err, data) => {
if (err) {
console.error('error baca:', err.message);
return;
}
console.log('isi callback:', JSON.stringify(data));
});
});isi callback: "data dari callback\n"Operasi writeFile dipanggil lebih dulu, dan readFile berada di dalam fungsi penerima dari writeFile sehingga urutannya terjamin. Bila readFile dipanggil di luar, isinya mungkin masih kosong karena writeFile belum selesai. Pola bersarang ini tidak terlihat rumit pada dua langkah, tetapi tumbuh cepat ketika operasi bertambah.
API berbasis promise#
Modul node:fs/promises menyediakan versi promise dari fungsi-fungsi fs yang sama, dengan nama tanpa akhiran Sync dan tanpa argumen callback. Fungsi-fungsi ini mengembalikan promise sehingga dapat dipakai dengan await di dalam fungsi async. Penanganan error cukup dilakukan dengan satu blok try/catch pada bagian terluar, dan urutan operasi tercermin dari susunan await tanpa bersarang.
const fs = require('node:fs/promises');
async function main() {
await fs.writeFile('catatan-promise.txt', 'data dari promise\n');
const data = await fs.readFile('catatan-promise.txt', 'utf8');
console.log('isi promise:', JSON.stringify(data));
await fs.appendFile('catatan-promise.txt', 'baris tambahan\n');
const data2 = await fs.readFile('catatan-promise.txt', 'utf8');
console.log('isi setelah append:', JSON.stringify(data2));
}
main().catch((err) => console.error('error:', err.message));isi promise: "data dari promise\n"
isi setelah append: "data dari promise\nbaris tambahan\n"Fungsi appendFile menambahkan data ke akhir berkas tanpa menimpa isi yang ada, dan readFile berikutnya membuktikan bahwa kedua tulisan tersimpan. Penanganan error lewat .catch pada pemanggilan main() menangkap segala error yang dilempar dari dalam fungsi async, sehingga kode tetap ringkas dan error tidak terlempar tanpa penangan.
Operasi direktori dan opsi tulis#
Selain membaca dan menulis berkas, modul fs menyediakan operasi direktori yang sama pentingnya. Fungsi readdir membaca daftar entri pada sebuah direktori, dan mkdir membuat direktori baru. Dengan opsi recursive: true pada mkdir, seluruh jalur direktori yang belum ada dibuatkan, sehingga mkdir('data/users/ali', { recursive: true }) sekaligus membuat data, data/users, dan data/users/ali bila belum ada. Fungsi rm menghapus berkas atau direktori, dan rm dengan recursive: true serta force: true menghapus seluruh isi direktori tanpa memeriksa keberadaan tiap entri. Fungsi rename mengubah nama atau memindahkan berkas antar direktori pada sistem berkas yang sama.
Fungsi writeFile menerima argumen opsi yang menentukan encoding string, hak akses berkas (mode dalam bentuk oktal), dan mode pembukaan berkas (flag). Posisi argumen opsi bervariasi tergantung tanda tangan yang dipakai: pada versi callback opsi menempati posisi ketiga sebelum callback, sedangkan pada versi promise opsi menempati posisi ketiga secara langsung. Nilai flag yang umum mencakup 'w' untuk menulis dari awal, 'a' untuk menambahkan, dan 'wx' untuk menulis tetapi gagal bila berkas sudah ada. Bendera 'wx' berguna untuk membuat berkas baru tanpa menimpa berkas lama secara tidak sengaja, dan sering dipakai pada penulisan berkas sementara yang harus unik.
const fs = require('node:fs/promises');
async function main() {
await fs.mkdir('data/users/ali/catatan', { recursive: true });
await fs.writeFile('data/users/ali/catatan/kunci.txt', 'abc123', { flag: 'wx' });
const daftar = await fs.readdir('data/users/ali/catatan');
console.log('isi direktori:', daftar);
await fs.rm('data/users', { recursive: true, force: true });
console.log('direktori data dihapus');
}
main().catch((err) => console.error('error:', err.message));isi direktori: [ 'kunci.txt' ]
direktori data dihapusDirektori data/users/ali/catatan dibuat dalam satu panggilan mkdir dengan opsi recursive, kemudian berkas kunci.txt ditulis dengan flag 'wx'. Pemanggilan readdir mengembalikan larik nama entri yang ada di dalam direktori, dan rm dengan recursive serta force menghapus seluruh pohon direktori. Pemakaian flag 'wx' membuat operasi gagal dengan EEXIST bila berkas sudah ada, yang berguna ketika penimpaan harus dicegah.
Kesalahan umum#
Pemakaian readFileSync di dalam penangan permintaan HTTP adalah kesalahan paling mahal karena satu berkas besar yang dibaca memblokir seluruh permintaan lain yang sedang diproses. Pengganti yang tepat adalah fs.readFile atau fs/promises yang menjalankan operasi tanpa memblokir. Kesalahan lain adalah mengabaikan argumen error pada callback, yang menyebabkan error tertelan dan operasi berikutnya dijalankan pada data yang tidak valid. Pemeriksaan if (err) pada baris pertama fungsi penerima wajib dilakukan.
Kebingungan antara fs.readFile tanpa opsi encoding dengan versi yang menyebutkan 'utf8' juga sering terjadi. Tanpa encoding, readFile mengembalikan Buffer berisi byte mentah, sedangkan dengan 'utf8' ia mengembalikan string. Penjelasan tentang Buffer ada pada topik terpisah. Untuk berkas teks, selalu sebutkan encoding agar operasi berikutnya bekerja pada string dan bukan byte.
Ringkasan#
- Tiga ragam API
fsberbagi nama fungsi:*Syncmemblokir, callback memakai error-first, dannode:fs/promisesmengembalikan promise. - API sinkron tepat untuk skrip pendek dan bagian startup, sedangkan permintaan HTTP memerlukan API asinkron agar throughput tidak turun.
fs.statmengembalikan objek dengansizeserta metodeisFiledanisDirectory, sedangkanfs.appendFilemenambah data tanpa menimpa.readFiletanpa encoding mengembalikanBuffer, sedangkanreadFiledengan'utf8'mengembalikan string.
Referensi#
- File system — Node.js
— Referensi resmi modul
fsdengan rincian setiap fungsi sinkron, callback, dan promise. - File system promises API — Node.js
— Bagian
fs/promisespada dokumentasi resmi yang menjelaskan API berbasis promise.