fs.writeFile(path, data, callback) は文字列やBufferをファイルに書き込みます。ファイルがなければNode.jsが作り、あれば元の中身が置き換えられます。fs.writeFileSync(path, data) は同じことを書き込み完了まで待って行い、fs.appendFile は置き換えずにファイルの末尾に追加します。
saved と、読み戻したテキストが表示されます。コールバックが受け取るのはエラー(または null)だけで、データは受け取りません。文字列の代わりに 42 を渡すと、呼び出しは TypeError を投げます。データは文字列かBufferでなければなりません。
writeFile、writeFileSync、fs/promises
3つの形は同じ引数を取り、結果の待ち方だけが違います。
const fs = require('fs');
const fsp = require('fs/promises');
fs.writeFileSync('a.txt', 'one'); // blocks, throws on error
fs.writeFile('b.txt', 'two', (err) => {}); // callback with err
await fsp.writeFile('c.txt', 'three'); // promise, use in async code
スクリプトや起動時のコードでは writeFileSync を、サーバーではPromise版を使いましょう。サーバーで同期の書き込みをすると、ディスクの処理が終わるまでほかのリクエストがすべて止まります。Promise APIの残りはfs/promisesのページにあります。
appendFileでファイルに追記する
writeFile はファイル全体を置き換えます。ログに1行足すなら appendFile を使います。これも初回はファイルを作ってくれます。
1回目の読み込みは "second\n" を表示します。2回目の writeFileSync が first を置き換えたからです。2回目の読み込みは "second\nthird\nfourth\n" を表示します(JSON.stringify で改行が見えるようにしています)。\n は自分で付けてください。どちらの関数も付けてくれません。
writeFile | appendFile | |
|---|---|---|
| ファイルがない | 作る | 作る |
| ファイルがある | 中身を置き換える | 末尾に追加する |
| デフォルトのフラグ | 'w' | 'a' |
| 主な使い道 | ドキュメントやJSONを丸ごと保存する | ログを1行ずつ書く |
上書きしない:flagオプション
第3引数にはオプションのオブジェクトを渡せます。その flag が、既存のファイルをどう扱うかを決めます。'wx' は「書き込むが、ファイルがすでにあれば失敗する」という意味で、ファイルを一度だけ作る安全な方法です。
2回目の呼び出しは EEXIST で失敗するので、ファイルの中身は abc123 のままです。2回目のファイル名を id2.txt に変えると、どちらの呼び出しも created を表示します。
よく使うフラグは、'w'(デフォルト、置き換え)、'a'(追記)、'wx'(作成のみ)、'ax'(追記するが、新しいファイルに限る)です。
先に fs.existsSync で確認してから書き込む方法には隙があります。確認と書き込みの間に、別のプロセスがファイルを作るかもしれないからです。'wx' は両方を1ステップで行います。
JSONをファイルに書き込む
writeFile はオブジェクトを受け付けません。JSON.stringify でテキストにしましょう。第3引数の 2 は出力をインデントして、ファイルを読みやすくします。
ファイルにはオブジェクトがインデントされた複数行で入り、それをパースし直すと同じ内容のオブジェクトになるので、最後の行は 2 を表示します。JSON.stringify を通さずにオブジェクトを渡すと、呼び出しは TypeError を投げます。
mkdirで先にフォルダを作る
writeFile が作るのはファイルで、フォルダは作りません。reports がないときに reports/2026/june.txt へ書き込むと ENOENT で失敗します。先に mkdir と { recursive: true } でパスを作りましょう。足りないフォルダをすべて作り、すでにあれば何もしません。
最初の書き込みは ENOENT で失敗します。mkdir の後は同じ書き込みが成功し、readdir は [ 'june.txt' ] を返します。実際のコードでは、Windowsでも動くようにこうしたパスを path.join で組み立てましょう。
よくある間違い
呼び出した直後にファイルが書き込まれていると思う。 fs.writeFile はデータがディスクに届く前に戻ります。ファイルを読むのも次の処理を始めるのも、コールバックの中で行うか、Promise版を await しましょう。
ループの中で書き込んでデータを失う。 項目ごとに writeFile を呼ぶと毎回ファイルが置き換わり、最後の項目しか残りません。appendFile を使うか、文字列全体を作ってから1回で書き込みます。
[object Object] と書き込んでしまう。 オブジェクトを String() やテンプレートリテラルに通すと [object Object] と書き込まれます。JSON.stringify を使いましょう。
よくある質問
fs.writeFileはファイルを上書きしますか?
します。デフォルトのフラグ 'w' ではファイルを空にしてから新しいデータを書くので、元の中身は消えます。末尾に足したいなら { flag: 'a' } を渡すか、appendFile を使います。
fs.writeFileは存在しないファイルを作りますか?
はい、ファイルは作ります。ただし、足りないフォルダは作りません。logs がないときに logs/app.log へ書き込むと ENOENT で失敗します。
データとして何を渡せますか?
文字列、Buffer、型付き配列です。オブジェクトや数値などそれ以外を渡すと TypeError が投げられるので、先にオブジェクトは JSON.stringify で、数値は String() で変換しましょう。
同じファイルにwriteFileを同時に何回も呼んでも安全ですか?
安全ではありません。1つのファイルに対して2つの writeFile を並行して呼ぶと、書き込みが混ざって中身がごちゃ混ぜになることがあります。1つが終わるのを待ってから次を始めるか、データをまとめて1回で書きましょう。