ファイル読み込み処理を書くたびにググっているので、まとめてみました。書き込みについては、読み込みとほぼ同じなので割愛します。
追記: fs/promises が最善
(2023/11/29 追記)
fs/promises というものが Node v10.0.0 で追加されていました。こちらの中にある readFile は始めから async になっています。
const readFile = require('fs/promises').readFile; const path = './hoge.txt'; const data = await readFile(path, 'utf8'); // これでhoge.txtの内容が読み出せる!
これが一番ファイルを読み込むカンタンな方法です。
以下は以前書いたものになります。
async/await + util.promisify (最適解っぽい)
async/awaitが使える環境なら(おそらく)これが最強です。
const readFile = require('util').promisify(require('fs').readFile); const path = './hoge.txt'; const data = await readFile(path, 'utf8'); // これでhoge.txtの内容が読み出せる!
メリット |
---|
短く可読性が高い |
例外処理も行うことができる |
処理をブロックしない |
async/awaitを使うパターン
const fs = require('fs'); const readFile = path => new Promise((resolve, reject) => { fs.readFile(path, 'utf8', (err, data) => { if (err) { reject(err); return; } resolve(data); }); }); // エラーを握りつぶしてもいいならreadFile()は次のようにできます // const readFile = path => new Promise(r => // fs.readFile(path, 'utf8', (_, data) => r(data))); const path = './hoge.txt'; const data = await readFile(path);
メリット |
---|
処理をブロックしない |
かなり読みやすい |
例外処理もできる |
async/awaitは使えるなら積極的に使ったほうが良いと思います。
async/await なしパターン
const fs = require('fs'); const path = './hoge.txt'; fs.readFile(path, 'utf8', (err, data) => { if (err) throw err; // something... })
メリット |
---|
処理をブロックしない |
このパターンは処理をブロックしないメリットはありますが、処理部分(something...)が中に埋まっていて、可読性が落ちています。
同期的に操作するパターン
const fs = require('fs'); const path = './hoge.txt'; const data = fs.readFileSync(path, 'utf8');
メリット | デメリット |
---|---|
シンプルに書ける | パフォーマンスが低下する |
可読性は高い |
このパターンはパフォーマンスがとても落ちるので、書き捨てる時以外はなるべく使用しないほうがいいです。
readStreamを使うパターン
const fs = require('fs'); const path = './hoge.txt'; const rs = fs.createReadStream(path, {highWaterMark: 10}); //bufferSizeではなくhighWaterMarkになった rs.setEncoding('utf8'); rs.on('data', data => console.log(data));
これは上3つとは異なるユースケースなので、メリット・デメリットを語ってもあまり意味がないですね。
このパターンは、大きいデータを読み込んで順次処理するのに向いています。
fs.openを使うパターン
これはめったに使わないと思います・・・いつ使うのでしょうか。
const fs = require('fs'); const path = './hoge.txt'; fs.open(path, 'r', (err, fd) => { fs.fstat(fd, (err, stats) => { const bufferSize = stats.size, buffer = new Buffer(bufferSize); // ここにデータが蓄積されていく let chunkSize = 5, // チャンクサイズ bytesRead = 0; // これまでに読んできたバイト数 while (bytesRead < bufferSize) { if (bytesRead + chunkSize > bufferSize) { chunkSize = bufferSize - bytesRead; } fs.read(fd, buffer, bytesRead, chunkSize, bytesRead, (err, bytesRead, buffer) => { }); bytesRead += chunkSize; // いままで読み込んだバイト数を更新 } console.log(buffer.toString('utf8')); // 読み終わった fs.close(fd, err => console.log(err)); }); });