ファイルシステムの基礎
Node.jsは標準でファイルやディレクトリを扱うためのAPIを提供しており、fsモジュールがその中心となる。非同期処理を前提としたプロミス版APIを使えば、スレッドをブロックすることなく効率的にI/Oを実行できる。
// プロミス版をインポート
import { promises as fsp } from 'fs';
ディレクトリの一覧取得
readdirにwithFileTypes: trueを渡すと、ファイル名の文字列ではなくDirentオブジェクトの配列が得られる。これにより、isFile()やisDirectory()などの判別メソッドが使える。
const entries = await fsp.readdir('./data', { withFileTypes: true });
for (const entry of entries) {
console.log(entry.name, entry.isDirectory() ? 'dir' : 'file');
}
再帰的なディレクトリ走査
ディレクトリを深く掘り下げてファイルを列挙するには、非同期再帰を利用する。Promiseを返すようにすることで、呼び出し元でawaitできる。
async function collectFiles(root) {
const results = [];
const stack = [root];
while (stack.length) {
const current = stack.pop();
const list = await fsp.readdir(current, { withFileTypes: true });
for (const node of list) {
const fullPath = `${current}/${node.name}`;
if (node.isDirectory()) {
stack.push(fullPath);
} else {
results.push(fullPath);
}
}
}
return results;
}
ファイル・ディレクトリの生成
ディレクトリを作成する
mkdirは親ディレクトリが存在しないと失敗するため、{ recursive: true }を付与すると階層ごと自動生成できる。
await fsp.mkdir('./logs/2024/06', { recursive: true });
新規ファイルへの書き込み
writeFileは同名ファイルが存在すると上書きする。追記したい場合はフラグを指定する。
await fsp.writeFile('./logs/app.log', 'start\n');
await fsp.writeFile('./logs/app.log', 'append\n', { flag: 'a' });
データの読み書きと加工
バッファから文字列へ
readFileはデフォルトでBufferを返す。utf8オプションを付けると文字列に変換される。
const raw = await fsp.readFile('./config.json', 'utf8');
const config = JSON.parse(raw);
パス操作のベストプラクティス
OSごとの区切り文字の違いを吸収するにはpathモジュールを活用する。
import path from 'path';
const target = path.join(__dirname, 'assets', 'images', 'logo.png');
const parsed = path.parse(target);
console.log(parsed.dir); // /home/user/project/assets/images
console.log(parsed.name); // logo
console.log(parsed.ext); // .png
実装例:設定ファイルの自動生成
以下は、指定ディレクトリ内の全画像パスをJSONにまとめて保存するスクリプトである。
import { promises as fsp } from 'fs';
import path from 'path';
async function buildImageIndex(dir) {
const files = await collectFiles(dir);
const images = files
.filter(f => ['.png', '.jpg', '.jpeg'].includes(path.extname(f)))
.map(f => path.relative(process.cwd(), f));
await fsp.writeFile(
path.join(dir, 'index.json'),
JSON.stringify(images, null, 2)
);
}
await buildImageIndex('./assets');