fs.readFile(path, 'utf8', callback) legge un file intero e passa il contenuto alla callback come stringa. fs.readFileSync(path, 'utf8') restituisce direttamente la stringa e aspetta che la lettura finisca, mentre await readFile(path, 'utf8') da fs/promises fa lo stesso senza bloccare. Se togli 'utf8' ottieni un Buffer di byte grezzi invece del testo.
Stampa per primo readFile called: readFile avvia solo la lettura, e la callback viene eseguita quando il contenuto è pronto. Cancella 'utf8', ed eseguilo di nuovo: la callback riceve <Buffer 42 75 79 20 6d 69 6c 6b 0a 43 61 6c 6c 20 41 64 61>, i byte grezzi del file.
readFile, readFileSync e fs/promises a confronto
Tutti e tre leggono lo stesso file. Cambia il modo in cui ottieni il risultato e se il resto del programma aspetta.
La riga sincrona stampa per prima perché nient'altro gira finché non ritorna. Le altre due finiscono dopo il codice principale, nell'ordine in cui terminano le loro letture.
readFileSync | readFile (callback) | readFile di fs/promises | |
|---|---|---|---|
| Restituisce | Il contenuto | undefined | Una promise del contenuto |
| Blocca il programma | Sì | No | No |
| Errori | Lanciati, usa try/catch | Primo argomento della callback | Promise rifiutata, try/catch con await |
| Da usare in | Codice di avvio e script | Vecchio codice a callback | Codice nuovo |
Usa readFileSync per leggere una config all'avvio o in uno script breve. In un server una lettura sincrona ferma tutte le altre richieste mentre il disco lavora, quindi lì usa la versione a promise. La pagina su fs/promises copre il resto di quell'API.
Gestire un file mancante (ENOENT)
Quando il file non esiste, l'errore ha code: 'ENOENT' ("error, no entry"). Controlla err.code per distinguere un file mancante da altri problemi, come un permesso negato.
La prima chiamata non trova il file e ripiega su default settings; la seconda legge dark mode. Rilanciare gli altri errori lascia visibili i problemi veri invece di usare i valori di default senza dire niente.
fs.existsSync: perché conviene provare subito a leggere
fs.existsSync(path) restituisce true o false, e viene la tentazione di controllare prima di leggere:
if (fs.existsSync('data.txt')) {
const text = fs.readFileSync('data.txt', 'utf8');
}
Sono due passaggi dove ne basta uno, e il file può essere cancellato tra i due, quindi la lettura può comunque lanciare un errore. Prova a leggere e gestisci ENOENT, come sopra. existsSync va bene quando ti serve solo sapere se qualcosa esiste senza aprirlo, per esempio per decidere se creare una cartella.
Leggere un file JSON
Leggi il testo, poi analizzalo con JSON.parse. Un file con un errore di sintassi lancia un SyntaxError, quindi tienilo nello stesso try.
Stampa 3001 e boolean: dopo il parsing i valori hanno i loro tipi JSON. Funziona anche require('./config.json'), ma mette in cache il risultato, quindi un secondo require restituisce il vecchio oggetto anche dopo che il file è cambiato.
Leggere un file riga per riga
Per un file che sta in memoria, leggilo tutto e dividilo sul carattere di a capo. Filtra la stringa vuota lasciata da un a capo finale.
La divisione dà 4 elementi, l'ultimo vuoto, quindi il ciclo stampa tre righe numerate. I file scritti su Windows chiudono le righe con \r\n; dividi su /\r?\n/ per gestire entrambi i casi.
Un log da diversi gigabyte non sta in memoria. Leggilo come stream, così tieni in memoria una riga alla volta:
const fs = require('fs');
const readline = require('readline');
async function main() {
const rl = readline.createInterface({
input: fs.createReadStream('big.log'),
crlfDelay: Infinity,
});
for await (const line of rl) {
console.log(line);
}
}
main();
Errori comuni
Usare il risultato fuori dalla callback. const text = fs.readFile(...) è undefined. Il contenuto esiste solo dentro la callback, o dopo await.
Dimenticare l'encoding. Senza 'utf8' ottieni un Buffer, e data.split('\n') lancia data.split is not a function. Passa l'encoding ogni volta che vuoi del testo.
Path relativi alla cartella sbagliata. 'data.txt' viene cercato dove è stato avviato node. Usa path.join(__dirname, 'data.txt') per un file che sta accanto al tuo script.
Domande frequenti
Perché fs.readFile restituisce undefined?
fs.readFile non restituisce il contenuto. Avvia la lettura e chiama la tua callback più tardi con (err, data). Usa i dati dentro la callback, chiama readFileSync oppure fai await della versione a promise.
Dove cerca Node un path relativo come 'data.txt'?
Nella directory di lavoro corrente, cioè la cartella da cui hai eseguito node, non la cartella dello script. Per leggere un file accanto allo script, costruisci il path con path.join(__dirname, 'data.txt').
fs.readFile può leggere un file da un URL?
No, legge solo dal file system. Per scaricare un file via HTTP usa fetch e poi await res.text().
Quanto può essere grande un file per readFile?
Carica tutto il file in memoria, quindi va bene per config, template e piccoli file di dati. Per file da centinaia di megabyte, leggili a pezzi con fs.createReadStream.