Wie füge ich eine Datei in Node hinzu?


505

Ich versuche, eine Zeichenfolge an eine Protokolldatei anzuhängen . WriteFile löscht den Inhalt jedoch jedes Mal, bevor die Zeichenfolge geschrieben wird.

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

Irgendeine Idee, wie man das auf einfache Weise macht?

Antworten:


799

Für gelegentliche Anhänge können Sie verwenden appendFile, wodurch bei jedem Aufruf ein neues Dateihandle erstellt wird:

Asynchron :

const fs = require('fs');

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

Synchron :

const fs = require('fs');

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

Wenn Sie jedoch wiederholt an dieselbe Datei anhängen, ist es viel besser, das Dateihandle wiederzuverwenden .


6
Seit Node v0.8.0
denysonique

59
Weiß jemand, ob fs.appendFile einen Link zur Datei offen hält, damit Anhänge schneller sind? (anstatt jedes Schreiben zu öffnen / schließen) nodejs.org/api/…
nelsonic

7
Falls es praktisch ist: Beachten Sie, dass dies asynchron ist. Dies kann zu seltsamem Timing und anderen Dingen führen. Beispiel: Wenn Sie process.exit()kurz danach haben fs.appendFile, können Sie beenden, bevor die Ausgabe gesendet wird. (Verwenden returnist in Ordnung.)
SilentSteel

6
Im schlimmsten Fall können Sie die synchrone Version verwenden appendFileSync. nodejs.org/api/… Möglicherweise verlieren Sie jedoch einen der großen Vorteile von Node, nämlich asynchrone Vorgänge. Stellen Sie sicher, dass Sie Fehler abfangen. Unter bestimmten Betriebssystemen wird Ihnen möglicherweise der Zugriff verweigert, wenn Sie gleichzeitig das Dateihandle anfordern. Nicht sicher, dass.
SilentSteel

5
@chrisdew Danke für das Update .. aber ... wenn wir die akzeptierte Antwort hier nicht verwenden sollen, was sollen wir dann tun? Wie haben Sie dieses Dilema gelöst?
Zipzit

215

Wenn Sie in einer Log - Datei schreiben wollen, das heißt Daten an das Ende einer Datei anhängen, nie verwenden appendFile. appendFileÖffnet ein Dateihandle für jedes Datenelement, das Sie Ihrer Datei hinzufügen. Nach einer Weile wird eine schöne EMFILEFehlermeldung angezeigt.

Ich kann hinzufügen, dass appendFiledas nicht einfacher zu bedienen ist als ein WriteStream.

Beispiel mit 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());

Bis zu 8000 auf meinem Computer können Sie Daten an die Datei anhängen, dann erhalten Sie Folgendes:

{ 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' }

Außerdem appendFilewird geschrieben, wenn es aktiviert ist, sodass Ihre Protokolle nicht per Zeitstempel geschrieben werden. Sie können mit Beispiel testen, 1000 anstelle von 100000 setzen, die Reihenfolge ist zufällig, hängt vom Zugriff auf die Datei ab.

Wenn Sie an eine Datei anhängen möchten, müssen Sie einen beschreibbaren Stream wie den folgenden verwenden:

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();

Sie beenden es, wenn Sie wollen. Sie müssen nicht einmal verwenden stream.end(), die Standardoption ist AutoClose:true, sodass Ihre Datei endet, wenn Ihr Prozess endet und Sie vermeiden, zu viele Dateien zu öffnen.


2
Das ist genau richtig.
Pogrindis

3
Vielen Dank für die großartige Antwort, aber ich bezweifle, dass Javascript aufgrund seiner asynchronen Natur stream.end()vor dem ausgeführt stream.write()wird. Daher sollten wir es nicht verwenden stream.end(), auch wie Sie bereits erwähnt haben. Dies AutoClose:Trueist eine Standardoption. Warum sollten Sie sich dann die Mühe machen, eine Zeile zu schreiben, die keine ist? verwenden.
Aashish Kumar

13
due to asynchronous nature of Javascript... was? Array.forEach ist eine synchrone Operation. JS ist synchron. Es bietet nur einige Möglichkeiten zum Verwalten von asynchronen Vorgängen, wie z. B. Versprechen und asynchrones / Warten.
Sharcoux

1
Ich würde vermuten, fs.appendFiledass zu viele geöffnete Dateien entstehen, weil Sie sie asynchron ausführen (Sie erstellen nur asynchron ein 10000-Dateihandle). Ich glaube, es appendFileSyncwürde kein ähnliches Problem geben, auch nicht fs.appendFilemit dem richtigen Intervall (1s ist wahrscheinlich mehr als genug). oder Warteschlangen.
Apfel Apfel

1
@RedwolfPrograms Für ausgelastetes Serverprotokoll möglicherweise wahr. Für einmaliges Protokoll pro Ausführung möglicherweise nicht. Wie auch immer, ich sage nur, dass der Punkt (zumindest der Grund) in dieser Antwort nicht korrekt ist.
Apfel Apfel

122

Ihr Code, der createWriteStream verwendet, erstellt für jeden Schreibvorgang einen Dateideskriptor. log.end ist besser, weil es den Knoten auffordert, unmittelbar nach dem Schreiben zu schließen.

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
fehlende erste Zeile! sollte 'var fs = require (' fs ') sein;'
Stormbytes

5
Oder vielleicht sogar noch besser var fs = require('graceful-fs'), was einige bekannte Probleme beseitigt hat. Weitere Informationen finden Sie in den Dokumenten .
Marko Bonaci

3
Sowohl die Anfangs- als auch die Endzeile befinden sich jedoch in derselben Zeile :-p
binki

5
Bitte beachten Sie : Wenn Sie verwenden fs.createWriteStream, verwenden Sie flags. Wenn Sie verwenden, fs.writeFiledann ist es flag. Weitere Informationen finden Sie unter Node JS Docs - File System .
Anish Nair

2
Achtung! Der Parameter ist nicht "flags", sondern "flag" (Singular): nodejs.org/api/…
Benny Neugebauer

25

Außerdem appendFilekönnen Sie ein Flag übergeben writeFile, um Daten an eine vorhandene Datei anzuhängen.

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

Durch Übergeben des Flags 'a' werden Daten am Ende der Datei angehängt.


3
Bitte beachten Sie : Wenn Sie verwenden fs.createWriteStream, verwenden Sie flags. Wenn Sie verwenden, fs.writeFiledann ist es flag. Weitere Informationen finden Sie unter Node JS Docs - File System .
Anish Nair

19

Sie müssen es öffnen und dann darauf schreiben.

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');
    });
  });
});

Hier sind einige Links, die zur Erläuterung der Parameter beitragen

offen
schreiben
schließen


BEARBEITEN : Diese Antwort ist nicht mehr gültig. Sehen Sie sich die neue Methode fs.appendFile zum Anhängen an.


1
Es sieht so aus, als ob Supercobra ständig ein Protokoll in die Protokolldatei schreibt. Die Verwendung von fs.write wird in diesem Fall nicht empfohlen. Verwenden Sie stattdessen fs.createWriteStream. Lesen Sie nodejs.org/docs/v0.4.8/api/all.html#fs.write
wütend Kiwi

10
Die Antwort ist ab nodejs v0.4.10 nicht mehr korrekt.
Ruben Tan

es sollte '0666' sein anstatt 666.
Ya Zhuang

13

Node.js 0.8 hat fs.appendFile:

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

Dokumentation


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

5
Alles, was mit sync () zu tun hat, ist fast immer eine schlechte Idee, es sei denn, Sie sind sich zu 100% sicher, dass Sie es unbedingt brauchen. Selbst dann machst du es wahrscheinlich falsch.
Zane Claes

4
Das heißt nicht, dass es falsch ist. Es macht es einfach synchron. Möglicherweise keine bewährte Methode für Node.js, wird jedoch unterstützt.
Luis R.

2
Ich habe "ur doin it false" im umgangssprachlichen Internet-Meme-Sinne verwendet. Offensichtlich wird es unterstützt = P
Zane Claes

7
Einverstanden mit Async, aber manchmal, wenn Sie nur ein interaktives Skript schreiben, ist die Synchronisierung in Ordnung.
Bryanmac

7
Synchrones Schreiben ist absolut in Ordnung, wenn Sie eine Einzelbenutzer-Befehlszeilen-App ausführen (z. B. ein Skript, um einige Dinge zu erledigen). Auf diese Weise ist es schneller, Dinge zu tun. Warum sollte der Knoten Synchronisierungsmethoden haben, wenn nicht für diesen Zweck?
Jan Święcki

3

Wenn Sie auf einfache und stressfreie Weise zeilenweise Protokolle in eine Datei schreiben möchten, empfehle ich 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');

Getestet mit Node v8.9.4.


2

Mein Ansatz ist etwas Besonderes. Ich benutze im Grunde die WriteStreamLösung, aber ohne das fd tatsächlich mit zu "schließen" stream.end(). Stattdessen benutze ich cork/uncork . Dies hatte den Vorteil einer geringen RAM-Auslastung (wenn dies für jemanden von Bedeutung ist) und ich glaube, dass es sicherer für die Protokollierung / Aufzeichnung ist (mein ursprünglicher Anwendungsfall).

Das Folgende ist ein ziemlich einfaches Beispiel. Beachten Sie, dass ich gerade eine Pseudo- forSchleife für die Präsentation hinzugefügt habe - im Produktionscode warte ich auf Websocket-Nachrichten.

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

uncork Leert die Daten im nächsten Tick in die Datei.

In meinem Szenario gibt es Spitzenwerte von bis zu ~ 200 Schreibvorgängen pro Sekunde in verschiedenen Größen. In der Nacht werden jedoch nur eine Handvoll Schreibvorgänge pro Minute benötigt. Der Code funktioniert auch in Spitzenzeiten sehr zuverlässig.


1

Ich biete diesen Vorschlag nur an, weil die Kontrolle über geöffnete Flags manchmal nützlich ist. Sie möchten beispielsweise zuerst eine vorhandene Datei abschneiden und dann eine Reihe von Schreibvorgängen anhängen. Verwenden Sie in diesem Fall beim Öffnen der Datei das Flag 'w' und schließen Sie es erst, wenn alle Schreibvorgänge abgeschlossen sind. Natürlich kann appendFile das sein, wonach Sie suchen :-)

  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

Verwenden von fs.appendFileoderfsPromises.appendFile sind die schnellsten und robustesten Optionen, wenn Sie etwas an eine Datei anhängen müssen.

Im Gegensatz zu einigen der vorgeschlagenen Antworten wird der Dateipfad, wenn er an die appendFileFunktion übergeben wird, tatsächlich von selbst geschlossen . Nur wenn Sie ein Dateihandle übergeben, das Sie von so etwas bekommen, müssen fs.open()Sie darauf achten, es zu schließen.

Ich habe es mit über 50.000 Zeilen in einer Datei versucht.

Beispiele:

(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.'
  );
})();

Geben Sie hier die Bildbeschreibung ein

Ref: https://github.com/nodejs/node/issues/7560
Beispielausführung: https://github.com/apickjs/apickFS/blob/master/writeLines.js


0

Hier ist ein vollständiges Skript. Geben Sie Ihre Dateinamen ein und führen Sie es aus und es sollte funktionieren! Hier ist ein Video-Tutorial zur Logik hinter dem Skript.

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

Ein einfacher Weg, dies zu tun, ist

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

Einfacher als was? Haben Sie die Top-Antwort überprüft, die genau die gleiche appendFileSyncLösung bietet?
Dan Dascalescu

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

Zusätzlich zur Antwort von appendFiledenysonique werden in NodeJS manchmal asynchrone und andere asynchrone Methoden verwendet, bei denen Versprechen zurückgegeben werden, anstatt Rückrufe weiterzuleiten. Dazu müssen Sie die Funktion mit promisifyHOF umschließen oder asynchrone Funktionen aus dem versprochenen Namespace importieren:

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

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

Ich hoffe es wird helfen 😉

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.