Come aggiungere a un file in Nodo?


505

Sto cercando di aggiungere una stringa a un file di registro. Tuttavia writeFile cancellerà il contenuto ogni volta prima di scrivere la stringa.

fs.writeFile('log.txt', 'Hello Node', function (err) {
  if (err) throw err;
  console.log('It\'s saved!');
}); // => message.txt erased, contains only 'Hello Node'

Qualche idea su come farlo nel modo più semplice?

Risposte:


799

Per accodamenti occasionali, è possibile utilizzare appendFile, che crea un nuovo handle di file ogni volta che viene chiamato:

In modo asincrono :

const fs = require('fs');

fs.appendFile('message.txt', 'data to append', function (err) {
  if (err) throw err;
  console.log('Saved!');
});

In modo sincrono :

const fs = require('fs');

fs.appendFileSync('message.txt', 'data to append');

Ma se aggiungi più volte lo stesso file, è molto meglio riutilizzare l'handle del file .


6
Dal Nodo v0.8.0
denysonique il

59
Qualcuno sa se fs.appendFile mantiene aperto un collegamento al file in modo che gli appendi siano più veloci? (piuttosto che aprire / chiudere ogni scrittura) nodejs.org/api/…
nelsonic,

7
Nel caso sia utile: si noti che questo è asincrono. Ciò può comportare tempi strani e altre cose. Es: se hai process.exit()subito dopo fs.appendFile, puoi uscire prima che venga inviato l'output. (Usare returnva bene.)
SilentSteel,

6
Caso peggiore, è possibile utilizzare la versione sincrona, appendFileSync. nodejs.org/api/… Ma potresti perdere uno dei grandi vantaggi di Node, ovvero le operazioni asincrone. Assicurati di rilevare errori. Forse su alcuni sistemi operativi, è possibile ottenere l'accesso negato se si richiede l'handle di file contemporaneamente. Non ne sono sicuro.
SilentSteel,

5
@chrisdew Grazie per l'aggiornamento .. ma ... se non dovessimo usare la risposta accettata qui, cosa dovremmo fare? Come hai risolto questo dilema?
zipzit

215

Quando si desidera scrivere in un file di registro, ovvero aggiungere dati alla fine di un file, non utilizzare maiappendFile . appendFileapre un handle di file per ogni pezzo di dati che aggiungi al tuo file, dopo un po 'ricevi un bellissimo EMFILEerrore.

Posso aggiungere che appendFilenon è più facile da usare di un WriteStream.

Esempio con appendFile:

console.log(new Date().toISOString());
[...Array(10000)].forEach( function (item,index) {
    fs.appendFile("append.txt", index+ "\n", function (err) {
        if (err) console.log(err);
    });
});
console.log(new Date().toISOString());

Fino a 8000 sul mio computer, è possibile aggiungere dati al file, quindi ottenere questo:

{ Error: EMFILE: too many open files, open 'C:\mypath\append.txt'
    at Error (native)
  errno: -4066,
  code: 'EMFILE',
  syscall: 'open',
  path: 'C:\\mypath\\append.txt' }

Inoltre, appendFilescriverà quando è abilitato, quindi i tuoi registri non saranno scritti dal timestamp. Puoi provare con l'esempio, impostare 1000 al posto di 100000, l'ordine sarà casuale, dipende dall'accesso al file.

Se si desidera aggiungere un file, è necessario utilizzare un flusso scrivibile come questo:

var stream = fs.createWriteStream("append.txt", {flags:'a'});
console.log(new Date().toISOString());
[...Array(10000)].forEach( function (item,index) {
    stream.write(index + "\n");
});
console.log(new Date().toISOString());
stream.end();

Lo finisci quando vuoi. Non è nemmeno richiesto l'uso stream.end(), l'opzione predefinita è AutoClose:true, quindi il file terminerà quando termina il processo ed eviti di aprire troppi file.


2
Questo è perfetto.
Pogrindis,

3
Grazie per l'ottima risposta, ma il mio dubbio è che a causa della natura asincrona di Javascript, verrà eseguito stream.end()prima di stream.write(), quindi non dovremmo usare stream.end(), anche come hai detto che AutoClose:Trueè un'opzione predefinita, quindi perché preoccuparsi di scrivere una riga che è di no uso.
Aashish Kumar,

13
due to asynchronous nature of Javascript... Che cosa? Array.forEach è un'operazione sincrona. JS è sincrono. Capita solo di fornire alcuni modi per gestire le operazioni asincrone, come Promises e async / waitit.
Sharcoux,

1
Immagino che fs.appendFilecomporti troppi file aperti perché lo esegui in modo asincrono (stai solo creando in modo asincrono 10000 handle di file), credo appendFileSyncche non avrebbe un problema simile, anche se non fs.appendFilecon un intervallo adeguato (1s è probabilmente più che sufficiente) o in coda.
mela mela

1
@RedwolfPrograms Per il log del server occupato, forse vero. Per il registro di una volta per esecuzione, forse no. Ad ogni modo, dichiaro solo che il punto (almeno il motivo) in questa risposta non è corretto.
mela mela

122

Il codice che utilizza createWriteStream crea un descrittore di file per ogni scrittura. log.end è migliore perché chiede al nodo di chiudere immediatamente dopo la scrittura.

var fs = require('fs');
var logStream = fs.createWriteStream('log.txt', {flags: 'a'});
// use {flags: 'a'} to append and {flags: 'w'} to erase and write a new file
logStream.write('Initial line...');
logStream.end('this is the end line');

6
prima riga mancante! dovrebbe essere 'var fs = require (' fs ');'
Stormbytes,

5
O forse anche meglio var fs = require('graceful-fs'), che ha eliminato alcuni problemi noti. Vedi i documenti per maggiori informazioni.
Marko Bonaci,

3
Sia la linea iniziale che quella finale sono sulla stessa linea però :-p
binki

5
Nota : se si utilizza fs.createWriteStream, quindi utilizzare flags. Se stai usando, fs.writeFileallora lo è flag. Fare riferimento a Nodo Documenti JS - File system per ulteriori informazioni.
Anish Nair,

2
Stai attento! Il parametro non è "flag" ma "flag" (singolare): nodejs.org/api/…
Benny Neugebauer

25

Inoltre appendFile, puoi anche passare un flag writeFileper aggiungere dati a un file esistente.

fs.writeFile('log.txt', 'Hello Node',  {'flag':'a'},  function(err) {
    if (err) {
        return console.error(err);
    }
});

Passando il flag 'a', i dati verranno aggiunti alla fine del file.


3
Nota : se si utilizza fs.createWriteStream, quindi utilizzare flags. Se stai usando, fs.writeFileallora lo è flag. Fare riferimento a Nodo Documenti JS - File system per ulteriori informazioni.
Anish Nair,

19

Devi aprirlo, quindi scrivergli.

var fs = require('fs'), str = 'string to append to file';
fs.open('filepath', 'a', 666, function( e, id ) {
  fs.write( id, 'string to append to file', null, 'utf8', function(){
    fs.close(id, function(){
      console.log('file closed');
    });
  });
});

Ecco alcuni link che aiuteranno a spiegare i parametri

apri
scrivi
chiudi


EDIT : questa risposta non è più valida, guarda nel nuovo metodo fs.appendFile per aggiungere.


1
sembra che la supercobra scriva costantemente il registro nel file di registro, in questo caso non è consigliabile utilizzare fs.write, utilizzare invece fs.createWriteStream. Leggi nodejs.org/docs/v0.4.8/api/all.html#fs.write
kiwi arrabbiato

10
La risposta non è più accurata a partire da nodejs v0.4.10.
Ruben Tan,

dovrebbe essere "0666" anziché 666.
Ya Zhuang

13

Node.js 0.8 ha fs.appendFile:

fs.appendFile('message.txt', 'data to append', (err) => {
  if (err) throw err;
  console.log('The "data to append" was appended to file!');
});

Documentazione


3
fd = fs.openSync(path.join(process.cwd(), 'log.txt'), 'a')
fs.writeSync(fd, 'contents to append')
fs.closeSync(fd)

5
qualcosa di sync () è quasi sempre una cattiva idea a meno che tu non sia sicuro al 100% di averne assolutamente BISOGNO. Anche allora, probabilmente stai sbagliando.
Zane Claes,

4
Non significa che sia sbagliato. Lo fa solo in modo sincrono. Potrebbe non essere la migliore pratica per Node.js, ma è supportato.
Luis R.

2
Stavo usando "ur doin it wrong" nel senso colloquiale di internet meme della frase. Ovviamente è supportato = P
Zane Claes il

7
Concordato su asincrono, ma a volte se stai solo scrivendo uno script interattivo, la sincronizzazione va bene.
bryanmac,

7
Scrivere in modo sincrono è assolutamente ok se stai facendo un'app a riga di comando per utente singolo (es. Script per fare alcune cose). In questo modo è più veloce fare cose. Perché il nodo dovrebbe avere metodi di sincronizzazione se non per questo scopo?
Jan Święcki,

3

Se vuoi un modo semplice e senza stress per scrivere registri riga per riga in un file, allora ti consiglio fs-extra :

const os = require('os');
const fs = require('fs-extra');

const file = 'logfile.txt';
const options = {flag: 'a'};

async function writeToFile(text) {
  await fs.outputFile(file, `${text}${os.EOL}`, options);
}

writeToFile('First line');
writeToFile('Second line');
writeToFile('Third line');
writeToFile('Fourth line');
writeToFile('Fifth line');

Testato con Nodo v8.9.4.


2

Il mio approccio è piuttosto speciale. Fondamentalmente uso la WriteStreamsoluzione ma senza "chiudere" effettivamente il file fd usando stream.end(). Invece io uso cork/ uncork. Ciò ha ottenuto il vantaggio di un basso utilizzo della RAM (se questo è importante per chiunque) e credo che sia più sicuro da usare per la registrazione / registrazione (il mio caso d'uso originale).

Di seguito è riportato un esempio piuttosto semplice. Si noti che ho appena aggiunto uno pseudo forloop per showcase - nel codice di produzione sto aspettando i messaggi di websocket.

var stream = fs.createWriteStream("log.txt", {flags:'a'});
for(true) {
  stream.cork();
  stream.write("some content to log");
  process.nextTick(() => stream.uncork());
}

uncork scaricherà i dati nel file con il segno di spunta successivo.

Nel mio scenario ci sono picchi fino a ~ 200 scritture al secondo in varie dimensioni. Di notte, tuttavia, sono necessarie solo poche scritture al minuto. Il codice funziona in modo super affidabile anche nelle ore di punta.


1

Offro questo suggerimento solo perché il controllo su flag aperti a volte è utile, ad esempio, potresti voler prima troncare un file esistente e quindi aggiungere una serie di scritture ad esso - nel qual caso usa il flag 'w' quando apri il file e non chiuderlo fino a quando tutte le scritture non sono state completate. Naturalmente appendFile potrebbe essere quello che stai cercando :-)

  fs.open('log.txt', 'a', function(err, log) {
    if (err) throw err;
    fs.writeFile(log, 'Hello Node', function (err) {
      if (err) throw err;
      fs.close(log, function(err) {
        if (err) throw err;
        console.log('It\'s saved!');
      });
    });
  });

1

Utilizzando il pacchetto jfile :

myFile.text+='\nThis is new line to be appended'; //myFile=new JFile(path);

1

Utilizzando fs.appendFileo fsPromises.appendFilesono le opzioni più veloci e robuste quando è necessario aggiungere qualcosa a un file.

Contrariamente ad alcune delle risposte suggerite, se il percorso del file viene fornito alla appendFilefunzione, in realtà si chiude da solo . Solo quando si passa a un filehandle che si ottiene da qualcosa di simile fs.open()è necessario occuparsi di chiuderlo.

L'ho provato con oltre 50.000 righe in un file.

Esempi:

(async () => {
  // using appendFile.
  const fsp = require('fs').promises;
  await fsp.appendFile(
    '/path/to/file', '\r\nHello world.'
  );

  // using apickfs; handles error and edge cases better.
  const apickFileStorage = require('apickfs');
  await apickFileStorage.writeLines(
    '/path/to/directory/', 'filename', 'Hello world.'
  );
})();

inserisci qui la descrizione dell'immagine

Rif: https://github.com/nodejs/node/issues/7560
Esempio di esecuzione: https://github.com/apickjs/apickFS/blob/master/writeLines.js


0

Ecco uno script completo. Inserisci i tuoi nomi di file ed eseguilo e dovrebbe funzionare! Ecco un tutorial video sulla logica dietro lo script.

var fs = require('fs');

function ReadAppend(file, appendFile){
  fs.readFile(appendFile, function (err, data) {
    if (err) throw err;
    console.log('File was read');

    fs.appendFile(file, data, function (err) {
      if (err) throw err;
      console.log('The "data to append" was appended to file!');

    });
  });
}
// edit this with your file names
file = 'name_of_main_file.csv';
appendFile = 'name_of_second_file_to_combine.csv';
ReadAppend(file, appendFile);

0

un modo più semplice per farlo è

const fs = require('fs');
fs.appendFileSync('file.txt', 'message to append into file');

Più facile di cosa? Hai controllato la risposta migliore, che offre esattamente la stessa appendFileSyncsoluzione?
Dan Dascalescu il

0
const inovioLogger = (logger = "") => {
    const log_file = fs.createWriteStream(__dirname + `/../../inoviopay-${new Date().toISOString().slice(0, 10)}.log`, { flags: 'a' });
    const log_stdout = process.stdout;
    log_file.write(logger + '\n');
}

0

Oltre alla risposta di denysonique , a volte appendFilevengono utilizzati tipi asincroni e altri metodi asincroni in NodeJS dove vengono restituiti risultati promettenti anziché passare il callback. Per farlo devi avvolgere la funzione con promisifyHOF o importare le funzioni asincrone dallo spazio dei nomi promesse:

const { appendFile } = require('fs').promises;

await appendFile('path/to/file/to/append', dataToAppend, optionalOptions);

Spero che possa aiutare 😉

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.