File system: sync e async
Prima di iniziare: le parole della lezione
- File system, encoding e Buffer
- Il file system organizza file e cartelle. L’encoding stabilisce come convertire byte in testo: UTF-8 è una scelta comune. Un Buffer contiene byte, non una stringa JavaScript.
- Sincrono e asincrono
- Una chiamata sincrona restituisce il risultato prima di proseguire e può bloccare il thread. Una chiamata asincrona avvia il lavoro e ne rende disponibile il risultato successivamente.
- Promise, async e await
- Una Promise rappresenta un esito futuro, riuscito o fallito. Una funzione
asyncrestituisce una Promise;awaitsospende quella funzione finché la Promise si risolve o fallisce. - try/catch
trydelimita operazioni che possono fallire;catchriceve l’errore e permette di gestirlo.
fs consente di leggere e scrivere file. Le operazioni *Sync bloccano il thread JavaScript fino al termine; per server e attività I/O frequenti preferisci le API asincrone.
// file.cjs
const fs = require('node:fs');
fs.writeFileSync('nota.txt', 'Prima riga\n');
fs.appendFileSync('nota.txt', 'Seconda riga\n');
console.log(fs.readFileSync('nota.txt', 'utf8'));
Stessa operazione con Promise:
// file-async.mjs
import { readFile, writeFile, appendFile } from 'node:fs/promises';
try {
await writeFile('nota.txt', 'Prima riga\n');
await appendFile('nota.txt', 'Seconda riga\n');
const testo = await readFile('nota.txt', 'utf8');
console.log(testo);
} catch (errore) {
console.error('Errore file:', errore.message);
}
Precisazione: writeFile sovrascrive per impostazione predefinita; appendFile aggiunge in fondo. Non mischiare letture e scritture concorrenti dello stesso file senza coordinarle.
Chi fa cosa, e perché
La versione a callback del corso segue la convenzione error-first: il primo parametro contiene l’eventuale errore, il secondo il risultato. Senza utf8, una lettura restituisce normalmente un Buffer. Se devi leggere due file e poi scrivere il contenuto combinato, devi aspettare entrambe le letture: posizionare la scrittura sotto le chiamate asincrone non basta.
Le Promise evitano di annidare molte callback. Due await consecutivi mantengono l’ordine delle operazioni; Promise.all può attendere più letture indipendenti. Non rende sicure scritture concorrenti sullo stesso file. Le API sincrone possono andare bene per piccoli script o preparazione iniziale; dentro una route rallentano anche gli altri utenti.
Un altro esempio guidato
// lettura.cjs — crea prima nota.txt nella cartella di avvio
const fs = require('node:fs');
console.log('1. Avvio lettura');
fs.readFile('nota.txt', 'utf8', (errore, testo) => {
if (errore) {
console.error('Lettura fallita:', errore.code);
return;
}
console.log('3. Contenuto:', testo);
});
console.log('2. Il programma può proseguire');
Come leggerlo e risultato atteso. Le righe 1 e 2 vengono stampate prima della callback. Se il file manca, leggi tipicamente ENOENT, codice che segnala un percorso inesistente. return impedisce di usare testo dopo l’errore. Il percorso relativo viene risolto dalla directory di lavoro.
Prova tu. Rinomina il file di input e osserva il ramo di errore; poi ripristinalo. Verifica che la scrittura con writeFile sostituisca davvero il contenuto precedente prima di usarla su dati importanti.