ディレクトリ検査ツール
メニューを表示するにはスワイプしてください
この章では、DirInspect Pro という高度なコンソールアプリケーションを作成する課題を紹介します。このアプリは、任意のディレクトリを徹底的に分析し、そのファイルやサブディレクトリに関する有益な統計情報を取得することを可能にします。
チャレンジ
重要なファイルやデータが含まれる複雑なフォルダ構造をナビゲートしなければならない状況を想像してください。DirInspect Pro はこの旅の頼もしい味方となり、ディレクトリの構造や内容について包括的な洞察を提供します。
完成するアプリ
DirInspect Pro の機能を活用する準備をしましょう。このアプリは、以下のような重要な情報を提供します。
- アイテムの総数
- すべてのアイテムの合計サイズ
- 最大ファイルの名前とサイズ
- 各ファイル名とサイズの詳細リスト
2つの選択肢
これから進む道は2つあります。
- 1つ目は、この課題に自力で取り組み、ガイダンスなしでスキルを磨く方法。
- 2つ目は、成功を保証する親切なガイドに従う方法。
どちらの道を選んでも、魅力的で実用的なコンソールアプリの作成という、やりがいのある旅が待っています。
マスタープラン
- ステップ 1: 必要なモジュールのインポート;
- ステップ 2: getStats 関数の定義;
- ステップ 3: analyzeFile 関数の定義;
- ステップ 4: analyzeDirectory 関数の定義;
- ステップ 5: main 関数の定義と実行;
- まとめ;
- アプリ全体のコード。
ステップ 1: 必要なモジュールのインポート
この冒険を始めるには、適切なツールが必要です。まず、2つの主要なモジュールをインポートします。fs.promises はファイルシステムを非同期で管理するため、path はファイルパスを効果的に扱うために使用します。
const fs = require("fs").promises;
const path = require("path");
- 1行目: 組み込みの
fsモジュールをインポートします。.promisesプロパティにより、Promise ベースの API にアクセスでき、非同期ファイル操作をasync/awaitで記述できます; - 2行目: 組み込みの
pathモジュールをインポートします。このモジュールは、ファイルやディレクトリのパス操作や正規化などのユーティリティを提供します。
ステップ2: getStats関数の定義
非同期関数getStatsは、ファイルまたはディレクトリのパスを引数として受け取り、fs.statを使用してその統計情報の取得を試みます。
- 成功した場合、統計情報を返却;
- エラーが発生した場合、エラーメッセージをログに出力し、
nullを返却します。
async function getStats(filePath) {
try {
const stats = await fs.stat(filePath);
return stats;
} catch (err) {
console.error("Error getting stats:", err.message);
return null;
}
}
- 1行目:
getStatsパラメータを受け取る非同期関数filePathを宣言; - 2行目、5行目: 非同期処理中のエラー処理のための
try...catchブロックを作成; - 3行目: 指定されたファイルのサイズ、作成日時、その他のメタデータを取得するために
await fs.stat(filePath)を使用; - 4行目:
statsが正常に完了した場合、fs.stat()オブジェクトを返却; - 6行目: 処理が失敗した場合、
console.error()でエラーメッセージをコンソールに出力; - 7行目: ファイル統計情報が取得できなかったことを示すために
nullを返却。
ステップ3: analyzeFile関数の定義
analyzeFile関数は、getStats関数を利用してファイルの統計情報を取得します。統計情報が利用可能(nullでない)場合、ファイル名(path.basenameで抽出)とサイズを含むオブジェクトを返却します。
async function analyzeFile(filePath) {
const stats = await getStats(filePath);
if (!stats) return null;
return {
name: path.basename(filePath),
size: stats.size,
};
}
- 1行目:
analyzeFileという非同期関数を宣言し、filePathパラメータを受け取る; - 2行目:
await getStats(filePath)を使用して、指定されたパスのファイル統計情報を取得; - 3行目:
statsが偽の場合を確認。統計情報が取得できなかった場合、関数はnullを返す; - 5〜8行目: ファイル名とファイルサイズを含むオブジェクトを作成して返す。ファイル名は
path.basename(filePath)で抽出し、サイズはstats.sizeから取得。
ステップ4: analyzeDirectory関数の定義
analyzeDirectory関数は、ディレクトリを走査し、その内容に関する完全な統計情報を収集。
動作概要: ディレクトリ内のすべての項目をfs.readdirで読み込む。各項目について:
path.joinでフルパスを構築;getStatsでファイルかフォルダかを判定;- ファイルの場合:
analyzeFileを呼び出して{ name, size }を取得;- 合計、最大ファイル、ファイルリストを更新;
- ディレクトリの場合:
- 再帰的に
analyzeDirectoryを呼び出す; - 結果を現在の統計情報に統合。
- 再帰的に
async function analyzeDirectory(directoryPath) {
let totalItems = 0;
let totalFiles = 0;
let totalSize = 0;
let largestFile = { name: "", size: 0 };
let fileList = [];
try {
const items = await fs.readdir(directoryPath);
for (const item of items) {
const itemPath = path.join(directoryPath, item);
const stats = await getStats(itemPath);
if (!stats) continue;
totalItems++;
if (stats.isFile()) {
const fileInfo = await analyzeFile(itemPath);
if (!fileInfo) continue;
totalFiles++;
totalSize += fileInfo.size;
if (fileInfo.size > largestFile.size) {
largestFile = fileInfo;
}
fileList.push(fileInfo);
} else if (stats.isDirectory()) {
const subDirectoryStats = await analyzeDirectory(itemPath);
totalItems += subDirectoryStats.totalItems;
totalFiles += subDirectoryStats.totalFiles;
totalSize += subDirectoryStats.totalSize;
if (subDirectoryStats.largestFile.size > largestFile.size) {
largestFile = subDirectoryStats.largestFile;
}
fileList = fileList.concat(subDirectoryStats.fileList);
}
}
return {
totalItems,
totalFiles,
totalSize,
largestFile,
fileList
};
} catch (err) {
console.error("Error analyzing directory contents:", err.message);
return {
totalItems: 0,
totalFiles: 0,
totalSize: 0,
largestFile: { name: "", size: 0 },
fileList: []
};
}
}
-
1行目:
analyzeDirectoryという非同期関数を宣言し、directoryPathパラメータを受け取る; -
2〜6行目: ディレクトリ統計情報を格納する変数(合計項目数、ファイル数、合計サイズ、最大ファイル、ファイルリスト)を初期化;
-
8行目: ファイルシステムエラーを処理するための
tryブロックを開始; -
9行目:
fs.readdir()でディレクトリの内容を読み込み、結果をitems配列に格納; -
11行目: ディレクトリ内の各項目を処理する
for...ofループを開始; -
12行目:
path.join()で現在の項目のフルパスを作成; -
13行目:
getStats()で現在の項目の統計情報を取得; -
14行目: 統計情報が取得できなかった場合はその項目をスキップ;
-
16行目: 正常に処理されたファイルまたはディレクトリごとに
totalItemsをインクリメント; -
18〜29行目: ファイル処理:
-
19行目:
analyzeFile()を呼び出してファイル名とサイズを取得; -
20行目: 解析に失敗した場合はファイルをスキップ;
-
22〜23行目: ファイル数と合計サイズを更新;
-
25〜27行目: 現在のファイルがこれまでで最大の場合は
largestFileを更新; -
29行目: ファイル情報を
fileListに追加; -
30〜42行目: ディレクトリ処理:
-
31行目: サブディレクトリに対して再帰的に
analyzeDirectory()を呼び出す; -
33〜35行目: サブディレクトリの統計情報を現在の合計に統合;
-
37〜39行目: サブディレクトリ内により大きなファイルがある場合は
largestFileを更新; -
41行目:
concat()でファイルリストを統合; -
45〜50行目: 最終的なディレクトリ統計情報を含むオブジェクトを返す;
-
52〜62行目: エラー時はメッセージを出力し、デフォルトの統計オブジェクトを返す。
ステップ5: main関数の定義と呼び出し
main関数はスクリプトのエントリーポイントです。この関数では解析対象のディレクトリパス(この場合は./docs)を指定し、analyzeDirectory関数を呼び出してディレクトリおよびその内容の統計情報を取得し、収集した情報を出力します。
この関数は以下を出力します。
- アイテムの総数
- ファイルの総数
- 合計サイズ
- 最大ファイルの詳細
- ディレクトリ内のファイル一覧
async function main() {
const directoryPath = "./docs";
const directoryStats = await analyzeDirectory(directoryPath);
console.log("Directory Analysis:");
console.log("Total items:", directoryStats.totalItems);
console.log("Total files:", directoryStats.totalFiles);
console.log("Total size (bytes):", directoryStats.totalSize);
console.log(
"Largest file:",
directoryStats.largestFile.name,
"Size:",
directoryStats.largestFile.size,
"bytes"
);
console.log("\nFile List:");
for (const file of directoryStats.fileList) {
console.log(file.name, "Size:", file.size, "bytes");
}
}
main();
-
1行目:
mainという非同期関数を宣言。 -
2行目: 解析対象ディレクトリのパスを格納する
directoryPath変数を定義。 -
3行目: 指定した
analyzeDirectory()をdirectoryPathで解析し、その結果をdirectoryStats変数にawaitで格納。 -
5~17行目:
console.log()でディレクトリ統計情報(アイテム総数、ファイル総数、合計サイズ、最大ファイル情報)を表示。 -
18~20行目:
fileListに格納されたdirectoryStats配列をループ処理。 -
ディレクトリ内の各ファイル名とサイズを出力。
-
23行目: 解析処理を開始するために
main()関数を呼び出し。
アプリ全体のコード
const fs = require("fs").promises;
const path = require("path");
async function getStats(filePath) {
try {
const stats = await fs.stat(filePath);
return stats;
} catch (err) {
console.error("Error getting stats:", err.message);
return null;
}
}
async function analyzeFile(filePath) {
const stats = await getStats(filePath);
if (!stats) return null;
return {
name: path.basename(filePath),
size: stats.size
};
}
async function analyzeDirectory(directoryPath) {
let totalItems = 0;
let totalFiles = 0;
let totalSize = 0;
let largestFile = { name: "", size: 0 };
let fileList = [];
try {
const items = await fs.readdir(directoryPath);
for (const item of items) {
const itemPath = path.join(directoryPath, item);
const stats = await getStats(itemPath);
if (!stats) continue;
totalItems++;
if (stats.isFile()) {
const fileInfo = await analyzeFile(itemPath);
if (!fileInfo) continue;
totalFiles++;
totalSize += fileInfo.size;
if (fileInfo.size > largestFile.size) {
largestFile = fileInfo;
}
fileList.push(fileInfo);
} else if (stats.isDirectory()) {
const subDirectoryStats = await analyzeDirectory(itemPath);
totalItems += subDirectoryStats.totalItems;
totalFiles += subDirectoryStats.totalFiles;
totalSize += subDirectoryStats.totalSize;
if (subDirectoryStats.largestFile.size > largestFile.size) {
largestFile = subDirectoryStats.largestFile;
}
fileList = fileList.concat(subDirectoryStats.fileList);
}
}
return {
totalItems,
totalFiles,
totalSize,
largestFile,
fileList
};
} catch (err) {
console.error("Error analyzing directory contents:", err.message);
return {
totalItems: 0,
totalFiles: 0,
totalSize: 0,
largestFile: { name: "", size: 0 },
fileList: []
};
}
}
async function main() {
const directoryPath = "./docs";
const directoryStats = await analyzeDirectory(directoryPath);
console.log("Directory Analysis:");
console.log("Total items:", directoryStats.totalItems);
console.log("Total files:", directoryStats.totalFiles);
console.log("Total size (bytes):", directoryStats.totalSize);
console.log(
"Largest file:",
directoryStats.largestFile.name,
"Size:",
directoryStats.largestFile.size,
"bytes"
);
console.log("\nFile List:");
for (const file of directoryStats.fileList) {
console.log(file.name, "Size:", file.size, "bytes");
}
}
main();
フィードバックありがとうございます!
AIに質問する
AIに質問する
何でも質問するか、提案された質問の1つを試してチャットを始めてください