なんだかGoodVibes

日々の勉強メモです。

【Node】トップディレクトリ配下のファイル検索

勉強用メモです。
本日は、トップディレクトリから
配下の全てのファイルとサイズを検索して
テキストに出力するサンプルです。
勉強のため、非同期で行っています。


概要

サンプルは以下の関数で構成されています。

  • main

    • メイン処理です。
  • readInput

    • 対象のパスを取得します。(ユーザー入力)
  • listDirFiles

  • writeResult

    • 結果をテキストに出力します。


サンプル

var readline = require('readline');
var fs = require('fs');
var path = require('path');
var dateutils = require('date-utils');

function main() {

    var text = '対象のパスを入力してください。\n =>';

    // メソッドチェーン
    readInput(text)
        .then(input => { return listDirFiles(input); })
        .then(lines => { writeResult(lines); })
        .catch(err => {console.log('失敗しました。')});
}

// --------------------------------
// 対象のパスを取得します。
// 引数    text:表示するテキスト
// 戻り値  入力されたパス
// --------------------------------
function readInput(text) {

    var r = readline.createInterface({
        input: process.stdin,
        output: process.stdout
    });

    return new Promise((resolve, reject) => {
        r.question(text, (answer) => {
            resolve(answer);
            r.close();
        });
    });
}

// ----------------------------------------------
// 再帰的にトップディレクトリ配下のファイルを取得
// 引数    input:対象のパス
// 戻り値  出力用文字列
// ----------------------------------------------
function listDirFiles(input) {

    // input配下のディレクトリとファイルを格納
    var lines = [];

    // 現在のパスを配列に格納
    lines.push(input);

    return new Promise((resolve, reject) => {
        fs.readdir(input, function(err, items) {
            if (err) {
                reject(err);
            } else {
                var tasks = [];
                items.forEach(function(name) {
                    var filePath = path.join(input, name);
                    if(fs.statSync(filePath).isDirectory()) {
                        // ディレクトリの場合はタスクを一旦配列に格納
                        tasks.push(listDirFiles(filePath));
                    } else {
                        // ファイルの場合はパス+サイズを配列に格納
                        var stat = fs.statSync(filePath);
                        var t = filePath + '(' + stat.size + ')';
                        lines.push(t);
                    }
                });

                // 全てのタスクが終了する、
                // もしくは1つでもrejectがあれば終了する
                Promise.all(tasks).then(results => {
                    results.forEach((items) => {
                        items.forEach((item) => {
                            lines.push(item);
                        });
                    });

                    resolve(lines);
                });
            }
        });
    });
}

// --------------------------------
// ファイルに書き込みを行う
// 引数    input:対象のパス
// --------------------------------
function writeResult(lines) {

    var resultDir = process.cwd() + "\\" + 'GetDirFiles';

    // 現在のパスの下に「GetDirFiles」が
    // 存在しなければを作成
    if (!fs.existsSync(resultDir)) {
        fs.mkdirSync(resultDir);
    }

    // 現在の日付をファイル名とする
    var dt = new Date();
    var fileName = dt.toFormat('YYYYMMDD') + '.txt';
    var resultFile = path.join(resultDir, fileName);

    // すでに存在する場合でも上書きする
    try {
        fs.writeFileSync(resultFile, lines.join('\n'), 'utf8');
        console.log('完了。');
    } catch (err) {
        console.log('失敗しました。');
    }
}

// メイン呼び出し
main();


まとめ

非同期処理、再帰処理…
非常に難しかったです。
もっと勉強しなければいけないなと思いました。
以上です。