Uvod
Razumevanje file sistema u Node.js ključno je za razvoj aplikacija koje zahtevaju čitanje, pisanje i manipulaciju fajlovima. Node.js nudi fs modul, koji omogućava sinhrono i asinhrono upravljanje fajlovima. Ovaj članak detaljno objašnjava kako koristiti fs modul u Node.js.
fs modul je deo Node.js API-ja koji omogućava rad sa fajl sistemom. Modul se može učitati korišćenjem require funkcije:
1 |
const fs = require('fs'); |
Čitanje fajlova
Da biste čitali sadržaj fajla, možete koristiti fs.readFile za asinhrono čitanje ili fs.readFileSync za sinhrono čitanje. Na primer:
Asinhrono čitanje sa callback-om:
1 2 3 4 5 6 7 8 |
const fs = require('fs'); fs.readFile('/putanja/do/fajla.txt', 'utf8', (err, data) => { if (err) { console.error(err); return; } console.log(data); }); |
Asinhrono čitanje sa promisima:
1 2 3 4 5 6 7 8 9 |
const fsPromise = require('fs/promises'); (async () => { try { const data = await fsPromise.readFile('/putanja/do/fajla.txt', 'utf8'); console.log(data); } catch (err) { console.error(err); } })(); |
Sinhrono čitanje:
1 2 3 4 5 6 |
try { const data = fs.readFileSync('/putanja/do/fajla.txt', 'utf8'); console.log(data); } catch (err) { console.error(err); } |
Pisanje u fajlove
Za pisanje u fajlove, fs modul nudi fs.writeFile za asinhrono pisanje i fs.writeFileSync za sinhrono pisanje. Na primer:
Asinhrono pisanje sa callback-om:
1 2 3 4 5 6 7 8 |
const fs = require('fs'); fs.writeFile('/putanja/do/fajla.txt', 'Sadržaj koji treba zapisati', (err) => { if (err) { console.error(err); return; } console.log('Fajl je uspešno zapisan!'); }); |
Asinhrono pisanje sa promisima:
1 2 3 4 5 6 7 8 9 |
const fsPromise = require('fs/promises'); (async () => { try { await fsPromise.writeFile('/putanja/do/fajla.txt', 'Sadržaj koji treba zapisati'); console.log('Fajl je uspešno zapisan!'); } catch (err) { console.error(err); } })(); |
Sinhrono pisanje:
1 2 3 4 5 6 |
try { fs.writeFileSync('/putanja/do/fajla.txt', 'Sadržaj koji treba zapisati'); console.log('Fajl je uspešno zapisan!'); } catch (err) { console.error(err); } |
Pisanje otvorenog fajla
Ukoliko želimo da imamo detaljnu kontrolu nad procesom pisanja, uključujući mogućnost da odredimo kako će se pisanje odvijati (kreiranje novog fajla, dodavanje na kraj postojećeg, itd.) i mogućnost upravljanja resursima onda možemo primeniti sledeći pristup:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
const fs = require('fs'); const content = 'Ovo je tekst koji želimo da zapišemo u fajl.'; // Otvorite fajl za pisanje fs.open('/putanja/do/fajla.txt', 'w', (err, fd) => { if (err) { return console.error('Greška pri otvaranju fajla:', err); } console.log(`Fajl otvoren za pisanje, file descriptor: ${fd}`); // Pišite u fajl koristeći file descriptor fs.write(fd, content, (err) => { if (err) { console.error('Greška pri pisanju u fajl:', err); return; } console.log('Tekst uspešno zapisan.'); // Zatvorite fajl nakon pisanja fs.close(fd, (err) => { if (err) { console.error('Greška pri zatvaranju fajla:', err); return; } console.log('Fajl zatvoren uspešno.'); }); }); }); |
Rad sa direktorijumima
fs modul takođe omogućava kreiranje, čitanje i brisanje direktorijuma. Na primer:
Kreiranje direktorijuma sa callback-om:
1 2 3 4 5 6 7 8 |
const fs = require('fs'); fs.mkdir('/putanja/do/novog/direktorijuma', { recursive: true }, (err) => { if (err) { console.error(err); return; } console.log('Direktorijum je kreiran!'); }); |
Kreiranje direktorijuma sa promisima:
1 2 3 4 5 6 7 8 9 |
const fsPromise = require('fs/promises'); (async () => { try { await fsPromise.mkdir('/putanja/do/novog/direktorijuma', { recursive: true }); console.log('Direktorijum je kreiran!'); } catch (err) { console.error(err); } })(); |
Čitanje sadržaja direktorijuma sa callback-om:
1 2 3 4 5 6 7 8 |
const fs = require('fs'); fs.readdir('/putanja/do/direktorijuma', (err, files) => { if (err) { console.error(err); return; } console.log(files); }); |
Čitanje direktorijuma sa promisima:
1 2 3 4 5 6 7 8 9 |
const fsPromise = require('fs/promises'); (async () => { try { const files = await fsPromise.readdir('/putanja/do/direktorijuma'); console.log(files); } catch (err) { console.error(err); } })(); |
Brisanje direktorijuma sa callback-om:
1 2 3 4 5 6 7 8 |
const fs = require('fs'); fs.rmdir('/putanja/do/direktorijuma', { recursive: true }, (err) => { if (err) { console.error(err); return; } console.log('Direktorijum je obrisan!'); }); |
Čitanje otvorenog fajla
Ukoliko ipak želimo da imamo finu kontrolu nad čitanjem, kao što je specifikacija tačne pozicije odakle želite početi čitanje unutar fajla i koliko podataka želite pročitati onda možemo koristiti sledeći pristup
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
const fs = require('fs'); // Prvo otvorite fajl da biste dobili file descriptor (fd) fs.open('/putanja/do/fajla.txt', 'r', (err, fd) => { if (err) { return console.error('Greška pri otvaranju fajla:', err); } console.log(`Fajl otvoren, file descriptor: ${fd}`); // Alocirajte buffer za čitanje sadržaja fajla const bufferSize = 1024; let buffer = Buffer.alloc(bufferSize); // Čitajte sadržaj fajla fs.read(fd, buffer, 0, bufferSize, null, (err, num) => { if (err) { console.error('Greška pri čitanju fajla:', err); return; } console.log(`Pročitano ${num} bajtova.`); // Prikaz sadržaja fajla console.log(buffer.slice(0, num).toString()); // Zatvorite fajl nakon čitanja fs.close(fd, (err) => { if (err) { console.error('Greška pri zatvaranju fajla:', err); return; } console.log('Fajl zatvoren uspešno.'); }); }); }); |
Bilo bi poželjno da buffer prilagodimo veličini fajla a to ćemo uraditi korišćenjem fs.fstat (ili fs.stat za asinhrono dobijanje informacija o fajlu pre čitanja), gde ćemo na taj način alocirati bafer tačno po meri sadržaja fajla, što čini čitanje efikasnijim, posebno za manje fajlove.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 |
const fs = require('fs'); // Prvo otvorite fajl da biste dobili file descriptor (fd) fs.open('/putanja/do/fajla.txt', 'r', (err, fd) => { if (err) { return console.error('Greška pri otvaranju fajla:', err); } console.log(`Fajl otvoren, file descriptor: ${fd}`); // Dobijte informacije o fajlu da biste utvrdili njegovu veličinu fs.fstat(fd, (err, stat) => { if (err) { console.error('Greška pri dobijanju informacija o fajlu:', err); return; } // Alocirajte buffer tačne veličine fajla const bufferSize = stat.size; let buffer = Buffer.alloc(bufferSize); // Čitajte sadržaj fajla fs.read(fd, buffer, 0, bufferSize, null, (err, num, readBuffer) => { if (err) { console.error('Greška pri čitanju fajla:', err); return; } console.log(`Pročitano ${num} bajtova.`); // Prikaz sadržaja fajla console.log(readBuffer.toString()); // Zatvorite fajl nakon čitanja fs.close(fd, (err) => { if (err) { console.error('Greška pri zatvaranju fajla:', err); return; } console.log('Fajl zatvoren uspešno.'); }); }); }); }); |
Brisanje direktorijuma sa promisima:
1 2 3 4 5 6 7 8 9 |
const fsPromise = require('fs/promises'); (async () => { try { await fsPromise.rm('/putanja/do/direktorijuma', { recursive: true, force: true }); console.log('Direktorijum je obrisan!'); } catch (err) { console.error(err); } })(); |
Praćenje promena fajla
U Node.js, watch metoda iz fs modula omogućava praćenje promena na fajlovima ili direktorijumima. Ova funkcionalnost je korisna kada želite da automatski odgovorite na promene, kao što su ažuriranja fajlova, bez potrebe za ručnim osvežavanjem ili ponovnim pokretanjem aplikacije. Evo kako funkcioniše:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
const fs = require('fs'); // Praćenje promena na fajlu const filename = '/putanja/do/fajla.txt'; fs.watch(filename, (eventType, filename) => { console.log(`Dogodila se promena: ${eventType}`); if (filename) { console.log(`Fajl koji je promenjen je: ${filename}`); } else { console.log('Fajl nije specificiran'); } }); |
Ili uz korišćenje promisa:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
const fs = require('fs'); (async () => { try { const watcher = await new Promise((resolve, reject) => { const watcher = fs.watch('/putanja/do/fajla.txt', (eventType, filename) => { console.log(`Dogodila se promena: ${eventType}`); if (filename) { console.log(`Fajl koji je promenjen je: ${filename}`); } else { console.log('Fajl nije specificiran'); } }); watcher.on('error', (error) => reject(error)); resolve(watcher); }); console.log('Nadgledanje je započeto.'); } catch (error) { console.error('Došlo je do greške prilikom pokretanja nadgledanja:', error); } })(); |
Kada koristite fs.watch, on može emitovati dva glavna tipa događaja: ‘change’ i ‘rename’. Događaj ‘change’ se odnosi na izmenu sadržaja fajla, dok ‘rename’ ukazuje na promenu u strukturi direktorijuma (npr. kreiranje novog fajla, preimenovanje ili brisanje fajla).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
const fs = require('fs'); (async () => { const watcher = fs.watch('/putanja/do/fajla_ili_direktorijuma', (eventType, filename) => { if (eventType === 'rename') { console.log(`'rename' događaj detektovan za ${filename}.`); // Ovde implementirajte logiku specifičnu za 'rename' događaj. // Napomena: 'rename' može ukazivati na kreiranje, brisanje ili preimenovanje fajla. } else if (eventType === 'change') { console.log(`'change' događaj detektovan za ${filename}.`); // Ovde implementirajte logiku specifičnu za 'change' događaj. // Ovo se odnosi na promene unutar fajla. } }); console.log('Nadgledanje je započeto.'); // Opcionalno: zaustaviti nadgledanje nakon nekog vremena setTimeout(() => { watcher.close(); console.log('Nadgledanje je zaustavljeno.'); }, 10000); // zaustavlja nadgledanje nakon 10 sekundi })(); |