Düğümdeki bir dosyaya nasıl eklenir?


505

Bir günlük dosyasına bir dize eklemek çalışıyorum . Ancak writeFile, dizeyi yazmadan önce içeriği her seferinde siler.

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

Bunu nasıl kolay bir şekilde yapacağınız hakkında bir fikriniz var mı?

Yanıtlar:


799

Ara sıra eklenenler için, appendFileher çağrıldığında yeni bir dosya tanıtıcısı oluşturarak kullanabilirsiniz :

Zaman uyumsuz olarak :

const fs = require('fs');

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

Senkron olarak :

const fs = require('fs');

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

Ancak aynı dosyaya tekrar tekrar eklerseniz , dosya tanıtıcısını yeniden kullanmak çok daha iyidir .


6
Düğüm v0.8.0 beri
denysonique

59
Herkes fs.appendFile dosya bağlantısını açık tutar böylece ekler daha hızlı olup olmadığını biliyor mu ? (her yazmayı açmak / kapatmak yerine) nodejs.org/api/…
nelsonic

7
Kullanışlı olması durumunda: Bunun zaman uyumsuz olduğunu unutmayın. Bu tuhaf zamanlamaya ve diğer şeylere neden olabilir. Örn: process.exit()hemen sonra fs.appendFilevarsa, çıktı gönderilmeden önce çıkabilirsiniz. (Kullanımı returniyidir.)
SilentSteel

6
Daha da kötüsü, senkron versiyonu kullanabilirsiniz appendFileSync. nodejs.org/api/… Ancak, zaman uyumsuz işlemler olan Düğüm'ün en büyük avantajlarından birini kaybedebilirsiniz. Hataları yakaladığınızdan emin olun. Belki de bazı işletim sistemlerinde, aynı anda dosya tanıtıcısı talep ederseniz erişim reddedilebilir. O konuda emin değilim.
SilentSteel

5
@chrisdew Güncelleme için teşekkürler .. ama ... burada kabul edilen cevabı kullanmayacaksak, ne yapmamız gerekiyor? Bu ikilemi nasıl çözdünüz?
zipzit

215

Bir günlük dosyasına yazmak istediğinizde, örneğin bir dosyanın sonuna veri eklemek istediğinizde, asla kullanmayın appendFile. appendFileDosyanıza eklediğiniz her veri parçası için bir dosya tanıtıcısı açar, bir süre sonra güzel bir EMFILEhata alırsınız .

Bunu appendFilekullanmaktan daha kolay olmadığını ekleyebilirim WriteStream.

İle örnek 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());

Bilgisayarımda 8000'e kadar, dosyaya veri ekleyebilirsiniz, sonra bunu elde edersiniz:

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

Dahası, appendFile etkinleştirildiğinde yazılacaktır, böylece günlükleriniz zaman damgası tarafından yazılmaz. Örnekle test edebilirsiniz, 100000 yerine 1000'i ayarlayın, sipariş rastgele olacak, dosyaya erişime bağlı.

Eğer bir dosyaya eklemek istiyorsanız, gereken böyle bir yazılabilir akışı kullanın:

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

İstediğiniz zaman bitirirsiniz. Kullanmanız bile gerekmez stream.end(), varsayılan seçenek, AutoClose:trueişleminiz sona erdiğinde dosyanız sona erer ve çok fazla dosya açmaktan kaçınırsınız.


2
Bu nokta.
18'de Pogrindis

3
Büyük cevap için teşekkürler, ama şüphem Javascript'in asenkron doğası nedeniyle, stream.end()önce yürütülecek stream.write(), bu yüzden kullanmamalıyız stream.end(), ayrıca belirttiğiniz gibi AutoClose:Truevarsayılan bir seçenek, o zaman neden hayır kullanın.
Aashish Kumar

13
due to asynchronous nature of Javascript... Ne? Array.forEach senkron bir işlemdir. JS eşzamanlıdır. Vaatler ve eşzamansız / beklemek gibi eşzamansız işlemleri yönetmek için bazı yollar sağlar.
Sharcoux

1
Ben fs.appendFileçok asenkron bir şekilde yürütmek çünkü çok fazla açık dosya sonucu tahmin ediyorum (sadece asenkron olarak 10000 dosya tanıtıcısı oluşturuyorsunuz), ben appendFileSyncde benzer bir sorun olmaz inanıyorum , fs.appendFileuygun aralık ile de (1s muhtemelen fazlasıyla yeterli) veya kuyruğa alma.
elma elması

1
@RedwolfPrograms Meşgul sunucu günlüğü için, belki doğrudur. Yürütme günlüğü başına bir defa için, belki değil. Her neyse, ben sadece bu cevaptaki noktanın (en azından nedeni) doğru olmadığını söylüyorum.
elma elması

122

CreateWriteStream kullanan kodunuz her yazma için bir dosya tanımlayıcı oluşturur. log.end daha iyidir çünkü düğümden yazma işleminden hemen sonra kapanmasını ister.

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
ilk satır eksik! 'var fs = requir (' fs ') olmalıdır;'
Stormbytes

5
Ya da belki de daha iyisi var fs = require('graceful-fs'), bilinen bazı sorunları ortaya çıkardı. Daha fazla bilgi için dokümanlara bakın .
Marko Bonaci

3
Hem başlangıç ve bitiş çizgisi :-p da aynı hat üzerinde olan
binki

5
Lütfen dikkat : kullanıyorsanız fs.createWriteStream, kullanın flags. Eğer kullanıyorsanız fs.writeFileo zaman flag. Daha fazla bilgi için lütfen Düğüm JS Belgeleri - Dosya Sistemi'ne bakın.
Anish Nair

2
Dikkatli ol! Parametre "bayraklar" değil "bayrak" (tekil): nodejs.org/api/…
Benny Neugebauer

25

Ayrıca appendFile, writeFilevarolan bir dosyaya veri eklemek için bir bayrak da iletebilirsiniz .

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

'A' işaretini ileterek, dosyanın sonuna veriler eklenir.


3
Lütfen dikkat : kullanıyorsanız fs.createWriteStream, kullanın flags. Eğer kullanıyorsanız fs.writeFileo zaman flag. Daha fazla bilgi için lütfen Düğüm JS Belgeleri - Dosya Sistemi'ne bakın.
Anish Nair

19

Açmanız ve yazmanız gerekiyor.

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

İşte parametreleri açıklamaya yardımcı olacak birkaç bağlantı


yaz
kapat


EDIT : Bu yanıt artık geçerli değil, eklemek için yeni fs.appendFile yöntemine bakın.


1
supercobra sürekli log günlük dosyasına yazar gibi görünüyor, bu durumda fs.write kullanımı önerilmez, bunun yerine fs.createWriteStream kullanın. Nodejs.org/docs/v0.4.8/api/all.html#fs.write
angry kiwi

10
Yanıt nodejs v0.4.10'dan itibaren artık doğru değil.
Ruben Tan

666 yerine '0666' olmalıdır.
Ya Zhuang

13

Node.js 0.8 şunlara sahiptir fs.appendFile:

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

belgeleme


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

5
100% 'e kesinlikle ihtiyacınız olduğundan% 100 emin olmadığınız sürece bir şey sync () neredeyse her zaman kötü bir fikirdir. O zaman bile, muhtemelen yanlış yapıyorsun.
Zane Claes

4
Bunun yanlış olduğu anlamına gelmez. Sadece eşzamanlı olarak yapar. Node.js için en iyi uygulama olmayabilir, ancak desteklenmektedir.
Luis

2
Cümlenin konuşma dili internet-meme anlamında "yanlış yapıyorsun" kullanıyordum. Açıkça desteklenmektedir = P
Zane Claes

7
Zaman uyumsuz olarak kabul edildi, ancak bazen yalnızca etkileşimli bir komut dosyası yazıyorsanız, senkronizasyon iyi olur.
bryanmac

7
Tek kullanıcılı komut satırı uygulaması (örneğin, bazı şeyler yapmak için komut dosyası) yapıyorsanız, eşzamanlı olarak yazmak kesinlikle tamamdır. Bu şekilde bir şeyler yapmak daha hızlı olur. Düğüm bu amaç için olmasa bile neden senkronizasyon yöntemlerine sahip olur?
Jan Święcki

3

Günlükleri bir dosyaya satır satır yazmanın kolay ve stressiz bir yolunu istiyorsanız, fs-extra'yı öneriyorum :

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

Düğüm v8.9.4 ile test edilmiştir.


2

Benim yaklaşımım oldukça özel. Temel olarak WriteStreamçözümü kullanıyorum ama aslında fd'yi kullanarak 'kapatmadan' stream.end(). Bunun yerine cork/uncork . Bu, düşük RAM kullanımı avantajına sahipti (bu herkes için önemliyse) ve günlük / kayıt (orijinal kullanım durumum) için kullanmanın daha güvenli olduğuna inanıyorum.

Aşağıda oldukça basit bir örnek var. Dikkat sadece forvitrin için bir sözde döngü ekledim - üretim kodunda websocket mesajlarını bekliyorum.

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

uncork bir sonraki onayda verileri dosyaya aktaracaktır.

Benim senaryomda çeşitli boyutlarda saniyede ~ 200 yazma tepeleri var. Ancak gece boyunca dakikada sadece bir avuç yazı gereklidir. Kod yoğun zamanlarda bile süper güvenilir çalışıyor.


1

Bu öneriyi yalnızca açık bayraklar üzerindeki kontrol bazen yararlı olduğu için öneriyorum, örneğin, önce mevcut bir dosyayı kısaltmak ve ardından bir dizi yazma eklemek isteyebilirsiniz - bu durumda dosyayı açarken 'w' bayrağını kullanın ve tüm yazılar tamamlanana kadar kapatmayın. Tabii appendFile peşinde ne olabilir :-)

  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

fs.appendFileVeya öğesini kullanmak fsPromises.appendFile, bir dosyaya bir şey eklemeniz gerektiğinde en hızlı ve en sağlam seçeneklerdir.

Önerilen cevapların bazılarının aksine, dosya yolu appendFileişleve sağlanırsa , aslında kendi kendine kapanır . Sadece bir dosya sapından geçtiğinizde,fs.open() aldığınız zaman onu kapatmaya dikkat etmeniz gerekir.

Bir dosyada 50.000'den fazla satırla denedim.

Örnekler:

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

resim açıklamasını buraya girin

Ref: https://github.com/nodejs/node/issues/7560
Örnek Yürütme: https://github.com/apickjs/apickFS/blob/master/writeLines.js


0

İşte tam bir senaryo. Dosya adlarınızı girin ve çalıştırın ve işe yarayacaktır! İşte betiğin arkasındaki mantıkla ilgili bir video eğitimi .

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

bunu yapmanın daha kolay bir yolu

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

Ne daha kolay? Aynı appendFileSyncçözümü veren en iyi yanıtı kontrol ettiniz mi?
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

Denysonique'in cevabına ek olarak, NodeJS'deki bazen eşzamansız tip appendFileve diğer eşzamansız yöntemler, geri arama geçişi yerine sözün döndüğü yerlerde kullanılır. Bunu yapmak için işlevi promisifyHOF ile sarmanız veya vaat ad alanından zaman uyumsuz işlevleri almanız gerekir :

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

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

Umarım yardımcı olur 😉

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.