ノードのファイルに追加する方法は?


505

ログファイルに文字列を追加しようとしています。ただし、writeFileは文字列を書き込む前に毎回コンテンツを消去します。

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

これを簡単に行う方法はありますか?

回答:


799

時々追加する場合は、を使用できますappendFile。これにより、呼び出されるたびに新しいファイルハンドルが作成されます。

非同期に:

const fs = require('fs');

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

同期的に:

const fs = require('fs');

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

ただし、同じファイルに繰り返し追加する場合は、ファイルハンドルを再利用することをお勧めします。


6
ノードv0.8.0以降
— denysonique

59
fs.appendFileがファイルへのリンクを開いたままにしていて、追加がより高速であるかどうかを誰かが知っていますか?(むしろオープン/クローズ各書き込みより)nodejs.org/api/...
— nelsonic

7
便利な場合:これは非同期であることに注意してください。これにより、奇妙なタイミングなどが発生する可能性があります。例:のprocess.exit()直後にfs.appendFileある場合、出力が送信される前に終了できます。(使用returnは問題あり
— ません

6
さらに悪いことに、同期バージョンを使用できますappendFileSync。nodejs.org/api/…しかし、非同期操作であるNodeの大きな利点の1つを失う可能性があります。エラーを確実にキャッチしてください。おそらく一部のOSでは、同時にファイルハンドルを要求すると、アクセスが拒否される可能性があります。わからない
— SilentSteel、2014

5
@chrisdew更新してくれてありがとう...しかし、ここで受け入れられた回答を使用しない場合は、どうすればよいですか?このジレマをどのように解決しましたか?
— zipzit 2016年

215

ログファイルに書き込む場合、つまりファイルの最後にデータを追加する場合は、を使用しないでくださいappendFile。appendFileしばらくすると、美しいEMFILEエラーが発生し、ファイルに追加する各データのファイルハンドルが開きます。

追加することappendFileができWriteStreamます。

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

私のコンピューターでは最大8000です。ファイルにデータを追加すると、次のようになります。

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

さらに、appendFile有効にすると書き込みが行われるため、ログはタイムスタンプで書き込まれません。たとえば、100000の代わりに1000を設定してテストできます。順序はランダムになり、ファイルへのアクセスに依存します。

ファイルに追加する場合は、次のような書き込み可能なストリームを使用する必要があります。

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

あなたがしたいときにそれを終了します。を使用する必要はありませんstream.end()。デフォルトのオプションはAutoClose:trueなので、プロセスが終了するとファイルは終了し、あまりにも多くのファイルを開かないようにします。


2
これはスポットです。
— ポグリンディス

3
素晴らしい答えをありがとう、しかし私の疑問はJavaScriptの非同期の性質のために、それがのstream.end()前に実行されるstream.write()ので、私たちは使用すべきではないのでstream.end()、あなたが言及したように、それAutoClose:Trueはデフォルトのオプションであり、そしてなぜわからない行を書くのか使用する。
— Aashish Kumar

13
due to asynchronous nature of Javascript... 何?Array.forEachは同期操作です。JSは同期です。たまたま、Promiseやasync / awaitなどの非同期操作を管理するいくつかの方法が提供されます。
— Sharcoux

1
fs.appendFile非同期で実行するため、開いているファイルが多すぎると思います(非同期に10000のファイルハンドルを作成しているだけです)。appendFileSync同様の問題はなくfs.appendFile、適切な間隔(1秒はおそらく十分すぎる)ではないと思います。またはキューイング。
— アップルアップル

1
@RedwolfPrograms多忙なサーバーログの場合は、おそらく真です。実行ログごとに1回のみの場合、そうではない可能性があります。とにかく、私はこの答えのポイント(少なくとも理由)が正しくないとだけ述べます。
— アップルアップル

122

createWriteStreamを使用するコードは、書き込みごとにファイル記述子を作成します。log.endは、書き込みの直後にノードに閉じるように要求するため、より優れています。

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
最初の行がありません!'var fs = require(' fs ');'である必要があります
— Stormbytes、2015

5
あるいはvar fs = require('graceful-fs')、いくつかの既知の問題を明らかにした、さらに良いかもしれません。詳しくはドキュメントをご覧ください。
— Marko Bonaci

3
:-p
— binki

5
注意:を使用している場合はfs.createWriteStream、を使用してくださいflags。あなたが使用している場合fs.writeFileはそれflagです。詳細については、Node JS Docs-File Systemを参照してください。
— Anish Nair 2017

2
注意してください!:パラメータは、「フラグ」が、「フラグ」(単数)ではないnodejs.org/api/...
— ベニーノイゲバウアー

25

に加えて、既存のファイルにデータを追加するためにappendFileフラグを渡すこともできwriteFileます。

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

フラグ 'a'を渡すと、データがファイルの最後に追加されます。


3
注意:を使用している場合はfs.createWriteStream、を使用してくださいflags。あなたが使用している場合fs.writeFileはそれflagです。詳細については、Node JS Docs-File Systemを参照してください。
— Anish Nair 2017

19

それを開いてから書き込む必要があります。

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

パラメータを説明するのに役立ついくつかのリンクがあります

オープン
書き込み
クローズ


編集:この回答は無効になりました。追加するための新しいfs.appendFileメソッドを調べてください。


1
スーパーコブラが常にログファイルにログを書き込むように見えます。この場合、fs.writeの使用は推奨されません。代わりにfs.createWriteStreamを使用してください。nodejs.org/docs/v0.4.8/api/all.html#fs.write
— 怒ったキウイ

10
nodejs v0.4.10以降、答えは正確ではなくなりました。
— ルーベンタン

それは0666 "ではなく666でなければなりません
— 雅荘


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

5
sync()は、絶対に必要であると100%確信していない限り、ほとんど常に悪い考えです。それでも、あなたはおそらくそれを間違っています。
— Zane Claes 2012年

4
それが間違っているという意味ではありません。同期的に行うだけです。Node.jsのベストプラクティスではないかもしれませんが、サポートされています。
— Luis R.

2
私は慣用句のインターネットミームの意味で「ur doin it wrong」を使用していました。明らかにサポートされています= P
— Zane Claes

7
非同期については同意しましたが、インタラクティブスクリプトを作成しているだけの場合は、同期で問題ありません。
— bryanmac 2014年

7
単一ユーザーのコマンドラインアプリを実行している場合(たとえば、何かを実行するためのスクリプト)は、同期的に記述しても問題ありません。そうすれば、作業を行うのが速くなります。この目的がなければ、ノードに同期メソッドがあるのはなぜですか?
— JanŚwięcki2014年

3

ファイルに1行ずつログを書き込む簡単でストレスのない方法が必要な場合は、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');

ノードv8.9.4でテスト済み。


2

私のアプローチはかなり特別です。私は基本的にWriteStreamソリューションを使用しますが、を使用してfdを実際に「閉じる」ことはありませんstream.end()。代わりにcork/ を使用しますuncork。これは、RAM使用量が少ないというメリットがあり(それが重要な場合)、ロギング/レコーディングに使用する方が安全だと思います(私の元の使用例)。

以下はかなり単純な例です。forショーケースに疑似ループを追加しただけであることに注意してください。本番コードでは、WebSocketメッセージを待機しています。

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

uncork 次のティックでデータをファイルにフラッシュします。

私のシナリオでは、さまざまなサイズで1秒あたり最大200回の書き込みのピークがあります。ただし、夜間は1分あたり数回の書き込みのみが必要です。コードはピーク時にも非常に信頼性の高い動作をします。


1

私は、オープンフラグを制御が便利な場合がありますという理由だけで、この提案を提供し、例えば、あなたが最初にそれを既存のファイルを切り捨て、したいことがあり、その後、それへの書き込みのシリーズを追加-フラグ「W」、その場合、使用中のファイルを開くときすべての書き込みが完了するまで閉じないでください。もちろんappendFileはあなたが望んでいるものかもしれません:-)

  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.appendFile場合fsPromises.appendFileは、or を使用するのが最も速く、最も堅牢なオプションです。

提案されたいくつかの回答とは対照的に、ファイルパスがappendFile関数に提供されている場合、 実際にはそれ自体が閉じます。あなたがファイルハンドルを渡すときだけ、あなたfs.open()はそれを閉じるような世話をしなければならないようなものを手に入れます。

ファイルに50,000行以上を入れてみました。

例:

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

ここに画像の説明を入力してください

参照:https : //github.com/nodejs/node/issues/7560
実行例:https : //github.com/apickjs/apickFS/blob/master/writeLines.js


0

これが完全なスクリプトです。ファイル名を入力して実行すると、問題なく機能するはずです。これは、スクリプトの背後にあるロジックに関するビデオチュートリアルです。

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

これを行う簡単な方法は

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

何よりも簡単ですか?まったく同じappendFileSync解決策を与える一番上の答えを確認しましたか?
— 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の回答に加えてappendFile、コールバックの受け渡しではなくpromiseが返されるNodeJSの非同期タイプやその他の非同期メソッドが使用される場合があります。これを行うには、promisifyHOFで関数をラップするか、Promise名前空間から非同期関数をインポートする必要があります。

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

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

お役に立てれば幸いです😉

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.