この記事は最終更新日から1年以上が経過しています。
@programming
投稿日 2020/6/23
更新日 2020/6/23 ✏
Node.js: 指定フォルダ配下のファイルを再帰的に取得
今回は3つの関数を用意しました。
walkSync(dir, suffix)
: 同期版walk(dir, suffix, cb)
: 非同期版 (並行処理)walks(dir, suffix, cb)
: 非同期版 (直列処理)
パラメータ
dir
: 指定フォルダのパス。suffix
: (オプション) 取得したいファイルのサフィックス。配列で複数指定も可能。無指定なら全て取得。cb
: (オプション) コールバック関数。
サンプルコード
同期版
/**
* Usage:
* $ node walkSync.js ~/path/to/find/ .js,.json
*/
const dir = process.argv[2]; // 検索フォルダ
const ext = process.argv[3]; // 拡張子(カンマ区切りOK)
const fs = require('fs');
const path = require('path');
/**
* 指定したフォルダ配下のファイルのパスを取得 (同期版)
*
* @param {String} dir - このパスの配下を検索
* @param {String|Array<String>} suffix - (option) ファイル名のサフィックス(拡張子とかを想定)
* @return {Array<String>} ヒットしたファイルのフルパスの一覧
*/
function walkSync(dir, suffix) {
let results = [];
let list = fs.readdirSync(dir);
list.forEach(function(file) {
file = path.resolve(dir, file);
let stat = fs.statSync(file);
if (stat && stat.isDirectory()) {
/* Recurse into a subdirectory */
results = results.concat(walkSync(file, suffix));
} else {
// NOTE: append files with specified suffix:
if (!suffix || suffix.length <= 0 || _hasSuffix(file, suffix)) {
results.push(file);
}
}
});
return results;
function _hasSuffix(filename, list) {
if (typeof list === "string") {
return filename.endsWith(list);
} else if (Array.isArray(list)) {
for (let len = list.length, i = 0; i < len; i++) {
const suffix = list[i];
if (filename.endsWith(suffix)) {
return true;
}
}
}
return false;
}
}
console.log("done:", walkSync(dir, ext.split(",")));
/*
$ node walkSync.js /home/hoge/test/ .js
done: [
'/home/hoge/test/app.js',
'/home/hoge/test/walk.js',
'/home/hoge/test/walks.js',
'/home/hoge/test/walkSync.js'
]
*/
非同期版 (並行処理)
/**
* Usage:
* $ node walk.js ~/path/to/find/ .js,.json
*/
const dir = process.argv[2]; // 検索フォルダ
const ext = process.argv[3]; // 拡張子(カンマ区切りOK)
const fs = require('fs');
const path = require('path');
/**
* 指定したフォルダ配下のファイルのパスを取得 (非同期版)
*
* ※並行(パラレル)に処理します。
*
* @param {String} dir - このパスの配下を検索
* @param {String|Array<String>} suffix - (option) ファイル名のサフィックス(拡張子とかを想定)
* @return {Array<String>} ヒットしたファイルのフルパスの一覧
*/
function walk(dir, suffix, done) {
let results = [];
fs.readdir(dir, function(err, list) {
if (err) return done(err);
let pending = list.length;
if (!pending) return done(null, results);
list.forEach(function(file) {
file = path.resolve(dir, file);
fs.stat(file, function(err, stat) {
if (stat && stat.isDirectory()) {
walk(file, suffix, function(err, res) {
results = results.concat(res);
if (!--pending) done(null, results);
});
} else {
// NOTE: append files with specified suffix:
if (!suffix || suffix.length <= 0 || _hasSuffix(file, suffix)) {
results.push(file);
}
if (!--pending) done(null, results);
}
});
});
});
function _hasSuffix(filename, list) {
if (typeof list === "string") {
return filename.endsWith(list);
} else if (Array.isArray(list)) {
for (let len = list.length, i = 0; i < len; i++) {
const suffix = list[i];
if (filename.endsWith(suffix)) {
return true;
}
}
}
return false;
}
}
walk(dir, ext.split(","), (err, res) => {
console.log("done:", res);
});
/*
$ node walk.js /home/hoge/test/ .js
done: [
'/home/hoge/test/app.js',
'/home/hoge/test/walk.js',
'/home/hoge/test/walks.js',
'/home/hoge/test/walkSync.js'
]
*/
非同期版 (直列処理)
/**
* Usage:
* $ node walks.js ~/path/to/find/ .js,.json
*/
const dir = process.argv[2]; // 検索フォルダ
const ext = process.argv[3]; // 拡張子(カンマ区切りOK)
const fs = require('fs');
const path = require('path');
/**
* 指定したフォルダ配下のファイルのパスを取得 (非同期版)
*
* ※直列(シリアル)に処理します。
*
* @param {String} dir - このパスの配下を検索
* @param {String|Array<String>} suffix - (option) ファイル名のサフィックス(拡張子とかを想定)
* @return {Array<String>} ヒットしたファイルのフルパスの一覧
*/
function walks(dir, suffix, done) {
let results = [];
fs.readdir(dir, function(err, list) {
if (err) return done(err);
let i = 0;
(function next() {
let file = list[i++];
if (!file) return done(null, results);
file = path.resolve(dir, file);
fs.stat(file, function(err, stat) {
if (stat && stat.isDirectory()) {
walks(file, suffix, function(err, res) {
results = results.concat(res);
next();
});
} else {
// NOTE: append files with specified suffix:
if (!suffix || suffix.length <= 0 || _hasSuffix(file, suffix)) {
results.push(file);
}
next();
}
});
})();
});
function _hasSuffix(filename, list) {
if (typeof list === "string") {
return filename.endsWith(list);
} else if (Array.isArray(list)) {
for (let len = list.length, i = 0; i < len; i++) {
const suffix = list[i];
if (filename.endsWith(suffix)) {
return true;
}
}
}
return false;
}
}
walks(dir, ext.split(","), (err, res) => {
console.log("done:", res);
});
/*
$ node walks.js /home/hoge/test/ .js
done: [
'/home/hoge/test/app.js',
'/home/hoge/test/walk.js',
'/home/hoge/test/walks.js',
'/home/hoge/test/walkSync.js'
]
*/
以上、割とよく使うテクニックのメモでした。