Modulo fs di NodeJS
Il modulo nativo fs di nodeJS abilita l'interazione con il file system. Tutte le operazioni che possiamo fare con il modulo fs possono essere fatte sia in modo sincrono che asincrono.
I metodi asincroni possono essere gestiti con con le callback oppure con le promise (preferibile) utilizzando le sintassi async await.
Lettura Asincrona da un file con readFile
Vediamo come creare un modulo per la lettura di un file in modo asincrono con readFile
app.js
// importiamo il modulo fs
const fs = require('fs');
/*
- come primo parametro, passiamo il percorso con il nome del file. In questo caso file1.txt
- come secondo parametro (opzionale) passiamo la codifica del file, in questo caso utf8
- come terzo parametro, passiamo la callback.
Il primo parametro della callback è sempre riservato agli errori,
quindi scriviamo l'oggetto err, e se non ci sono degli errori i dati del file
*/
fs.readFile('file1.txt', 'utf8' , (err, dati) =>{
//se ci sono degli errori, solleviamo un eccezzione con throw passando l'oggetto err
if(err) throw err;
console.log(dati);
});
Gestione dell'errore con readFile (asincrono)
Possiamo gestire gli errori con readFile usando sia gli eventi che definendo una funzione apposita.
Non è possibile usare try catch perchè opera in modo sincrono.
Facciamo un esempio: Proviamo a leggere da un file non esistente con readFile generando quindi un errore che gestiremo definendo una funzione (esempio readfile-err-fn.js) e un altro che gestiremo con gli eventi (esempio readfile-err-evt.js)
Gestione dell'errore definendo una funzione
readfile-err-fn.js
const fs = require('fs');
fs.readFile('file2.txt', (err, data) => {
if(err) {
return handleError(new Error(err));
}
console.log(err, data);
});
function handleError(errore) {
console.log('errore gestito');
};
Spiegazione step by step:
const fs = require('fs');
Importiamo il modulo nativo fs di node
fs.readFile('file2.txt', (err, data) => {
passiamo come primo parametro il file (inesistente) e come secondo parametro la callback di gestione che riceverà come primo parametro l'oggetto err se ci sono errori e come secondo parametro i dati del file se non ci sono errori.
if(err) {
return handleError(new Error(err));
}
console.log(err, data);
});
se ci sono errori, invochiamo la funzione handleError passando in input una nuova istanza della classe Error. Per uscire dal codice usiamo return;
function handleError(errore) {
console.log('errore gestito');
};
Per gestire l'errore in modo semplice definiamo una funzione handleError(errore) con un semplice console.log di esempio che indica che l'errore è stato gestito
Gestione dell'errore con un evento
readfile-err-evt.js
const fs = require('fs');
const { EventEmitter } = require('events');
const customEmitter = new EventEmitter();
fs.readFile('file2.txt', (err, data) => {
if(err) {
return customEmitter.emit('error',err);
}
console.log(err, data);
});
customEmitter.on('error', eventoErrore => console.log('errore gestito'));
Spiegazione step by step:
const fs = require('fs');
const { EventEmitter } = require('events');
const customEmitter = new EventEmitter();
Importiamo il modulo nativo fs di node
Importiamo la classe EventEmitter
Definiamo un'instanza di EventEmitter
fs.readFile('file2.txt', (err, data) => {
passiamo come primo parametro il file (inesistente) e come secondo parametro la callback di gestione che riceverà come primo parametro l'oggetto err se ci sono errori e come secondo parametro i dati del file se non ci sono errori.
if(err) {
return customEmitter.emit('error',err);
}
console.log(err, data);
se ci sono errori, andiamo a sollevare un evento, mettiamo come nome dell'evento ad esempio error e passiamo come parametro err, per uscire dal codice usiamo return;
customEmitter.on('error', eventoErrore => console.log('errore gestito'));
Definiamo un listener per l'evento error e definiamo la callback di gestione eventoErrore e restituiamo un console.log con il valore errore gestito.
Lettura Asincrona da un file con readFile
In Javascript per risolvere il problema noto come callback hell sono state inventate le promise (ES6).
In node possiamo leggere un file in modo asincrono ed utilizzando le promise con fs.promises.readFile
Nella versione ES6 di Javascript possiamo usare promise then catch
readFile-promise.js
const fs = require('fs');
fs.promises.readFile('file2.txt','utf-8')
.then(dati => console.log(dati))
.catch(errore => console.log(errore));
Spiegazione step by step:
fs.promises.readFile('file2.txt','utf-8')
Passiamo come primo parametro il percorso ed il file, e come secondo parametro la codifica del file.
.then(dati => console.log(dati))
Per gestire la risoluzione della promise usiamo il metodo then che riceverà in input i dati del file.
.catch(errore => console.log(errore));
Per gestire gli errori della promise rigettata, usiamo .catch e definiamo la callback che riceverà in input l'oggetto errore
Nelle versioni successive ad ES6 possiamo usare la sintassi async await
readFile-promise-async.js
const fs = require('fs');
async function leggi(leggiquesto) {
const dati = await fs.promises.readFile(leggiquesto, 'utf8');
console.log(dati);
};
leggi('file1.txt').catch(err => console.log(err));
leggi('file2.txt').catch(err => console.log(err));
Spiegazione step by step:
async function leggi(leggiquesto) {
definiamo una funzione asincrona che riceverà il percorso ed il nome del file da cui leggere
const dati = await fs.promises.readFile(leggiquesto, 'utf8');
console.log(dati);
attendere la risoluzione della promise , passiamo come primo parametro il percorso ed il nome del file, il questo caso la variabile leggiquesto e come secondo parametro la codifica utf-8
leggi('file1.txt').catch(err => console.log(err));
Invochiamo la funzione leggi passando in input il percorso ed il nome del file. Per gestire gli eventuali errori usiamo .catch, definamo la callback con l'oggetto err.
Scrivere in un file in modo asincrono con fs.writeFile e fs.promises.writeFile
Per scrivere in un file in modo asincrono il modo più semplice è utilizzare writeFile
writeFile.js
const fs = require('fs');
fs.writeFile('scrivifile.txt','YuppiDoH!', err => {
if(err) throw err;
console.log('File scritto correttamente');
});
Spiegazione step by step:
fs.writeFile('scrivifile.txt','YuppiDoH!', err => {
Passiamo come primo parametro il percorso ed il file, e come secondo parametro quello che vogliamo scrivere all'interno del file, come terzo parametro la callback che riceverà l'oggetto err in caso di errore.
if(err) throw err;
console.log('File scritto correttamente');
Per gestire il problema usiamo genericamente un if(err) throw err; (soluzione non ottimale)
Utilizzare writeFile con le promises
writeFile-promises.js
const fs = require('fs');
fs.promises.writeFile('scrivifile2.txt','YuppiDoh2!')
.then(()=> console.log('Scrittura avvenuta')) ;
Spiegazione step by step:
fs.promises.writeFile('scrivifile2.txt','YuppiDoh2!')
assiamo come primo parametro il percorso ed il file, e come secondo parametro quello che vogliamo scrivere all'interno del file.
fs.promises.writeFile('scrivifile2.txt','YuppiDoh2!')
.then(()=> console.log('Scrittura avvenuta')) ;
Il metodo then() prende due parametri: il primo parametro è la funzione che verrà eseguita nel caso in cui la promise venga risolta; il secondo parametro è la funzione che verrà eseguita se la promise viene rigettata. In questo caso però ci interessa sono il primo parametro dove vogliamo restituire la dicitura scrittura avvenuta, una volta scritto nel file.
Aggiungere del contenuto ad un file
Tutti i metodi visti fin ora per scrivere all'interno dei file, vanno a cancellare il contenuto ed aggiungere il contenuto descritto all'interno del codice. Se invece volessimo soltanto aggiungere del contenuto al contenuto già esistente possiamo usare appendFile.
Utilizzare appendFile per aggiungere contenuto ad un file
appendFile.js
const fs = require('fs');
fs.appendFile('scrivifile.txt','\n Questo è il contenuto aggiunto!', err => {
if(err) throw err;
console.log('Il contenuto è stato aggiunto correttamente');
});
Utilizzare appendFile con le promises
appendFile-promises.js
const fs = require('fs');
fs.promises.appendFile('scrivifile2.txt','\n \n \n YuppiDoh2!')
.then(() => console.log('Contenuto aggiunto correttamente')) ;