Panda Noir

JavaScript の限界を究めるブログでした。最近は幅広めに書いてます。

Node.jsのFile操作まとめ

ファイル読み込み処理を書くたびにググっているので、まとめてみました。書き込みについては、読み込みとほぼ同じなので割愛します。

async/await + util.promisify

たぶんこれが最強です。

const fs = require('fs');
const util = require('util');
const path = './hoge.txt';

const readFile = (...args) => util.promisify(fs.readFile)(...args);

(async () => {
    const data = await readFile(path, 'utf8');
})();

短い上に可読性も高いです。

async/await

const fs = require('fs');
const path = './hoge.txt';
const jsonPath = './hoge.json';

const readFile = path => new Promise((resolve, reject) => {
    fs.readFile(path, 'utf8', (err, data) => {
        if (err) { reject(err); return; }
        resolve(data);
    });
});

// エラーを握りつぶしてもいいなら
// const readFile = path => new Promise(r =>
//     fs.readFile(path, 'utf8', (_, data) => r(data)));

(async () => {
    const data = await readFile(path);
    const json = JSON.parse(await readFile(jsonPath));
})();

かなり読みやすいです。async/awaitが使えるなら積極的に使いましょう。

async/await なし

const fs = require('fs');
const path = './hoge.txt';

fs.readFile(path, 'utf8', (err, data) => {
    if (err) throw err;
    someFunc(data);
});

非同期で読み込みます。ただし、someFuncが中に埋まってしまっていて可読性が落ちています。

同期的に操作する

const fs = require('fs');
const path = './hoge.txt';

const data2 = fs.readFileSync(path, 'utf8');

同期的読み込みはあまり良くないので、書き捨てる時以外は使用しないほうがいいです。

readStreamを使う

const fs = require('fs');
const path = './hoge.txt';
const jsonPath = './hoge.json';

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