# 機能設計書 45-ディレクトリ走査

## 概要

Julia Base ライブラリにおけるディレクトリ内容の列挙・再帰的走査を提供する機能の設計書である。

### 本機能の処理概要

**業務上の目的・背景**：ファイルシステム上のディレクトリ内容を列挙し、特定のパターンに一致するファイルを検索する操作はデータ処理やビルドシステムなどで頻繁に必要となる。本機能はディレクトリの内容を効率的に走査し、必要に応じてフィルタリングや再帰的探索を行う API を提供する。

**機能の利用シーン**：ディレクトリ内のファイル一覧の取得、特定の拡張子を持つファイルの検索、ディレクトリツリーの再帰的走査、ファイル操作（バッチ処理）の対象ファイルの列挙など。

**主要な処理内容**：
1. `readdir` によるディレクトリ内容の列挙（ソート済み）
2. `walkdir` によるディレクトリツリーの再帰的走査
3. `readdir` の `join` オプションによるフルパス生成
4. `readdir` の `sort` オプションによるソート制御
5. `walkdir` の `topdown` / `follow_symlinks` / `onerror` オプション

**関連システム・外部連携**：OS のディレクトリ読み取り API（libuv の `uv_fs_scandir` 等）を使用。

**権限による制御**：ディレクトリの読み取り権限（`r`）と実行権限（`x`）が必要。権限不足の場合はエラーが発生する。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | CLI / REPL | 主画面 | readdir/walkdir の対話的実行 |

## 機能種別

情報取得 / ファイルシステム操作

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| dir | AbstractString | No | 走査対象ディレクトリ（デフォルト: "."） | ディレクトリが存在すること |
| join | Bool | No | フルパスを返すか（デフォルト: false） | readdir のみ |
| sort | Bool | No | ソートするか（デフォルト: true） | readdir のみ |
| topdown | Bool | No | トップダウン走査（デフォルト: true） | walkdir のみ |
| follow_symlinks | Bool | No | シンボリックリンク追従（デフォルト: false） | walkdir のみ |
| onerror | Function | No | エラー時コールバック（デフォルト: throw） | walkdir のみ |

### 入力データソース

ユーザーコードからファイルパス文字列として渡される。

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| entries | Vector{String} | readdir の場合のファイル名/パスの配列 |
| (root, dirs, files) | Tuple{String, Vector{String}, Vector{String}} | walkdir の各ステップの結果 |

### 出力先

関数の戻り値としてユーザーコードに返される。walkdir はイテレータとして遅延評価される。

## 処理フロー

### 処理シーケンス

```
1. ディレクトリパスの受け取り
   └─ デフォルトは現在のディレクトリ "."
2. ディレクトリの読み取り
   └─ libuv 経由でディレクトリエントリを取得
3. オプション処理
   └─ sort=true: エントリをアルファベット順ソート
   └─ join=true: dirname と結合してフルパスに変換
4. walkdir の場合: 再帰処理
   └─ topdown=true: 親→子の順で yield
   └─ topdown=false: 子→親の順で yield
```

### フローチャート

```mermaid
flowchart TD
    A[ディレクトリパス入力] --> B{readdir or walkdir?}
    B -->|readdir| C[uv_fs_scandir 呼出]
    C --> D{sort?}
    D -->|Yes| E[sort! 実行]
    D -->|No| F[ソートなし]
    E --> G{join?}
    F --> G
    G -->|Yes| H[joinpath で結合]
    G -->|No| I[ファイル名のみ]
    H --> J[Vector{String} 返却]
    I --> J
    B -->|walkdir| K[Channel ベースのイテレータ生成]
    K --> L[readdir で内容取得]
    L --> M{topdown?}
    M -->|Yes| N[current を yield]
    N --> O[サブディレクトリを再帰]
    M -->|No| P[サブディレクトリを先に再帰]
    P --> Q[current を yield]
    O --> R[完了まで繰り返し]
    Q --> R
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-45-01 | デフォルトソート | readdir のデフォルトはアルファベット順ソート | sort 未指定時 |
| BR-45-02 | `.` と `..` の除外 | readdir は `.` と `..` を結果に含めない | 常時 |
| BR-45-03 | walkdir のシンボリックリンク | follow_symlinks=false（デフォルト）ではシンボリックリンクを追従しない | walkdir |
| BR-45-04 | walkdir のエラー処理 | onerror コールバックが指定されない場合、エラーは throw される | walkdir |
| BR-45-05 | walkdir の遅延評価 | walkdir は Channel ベースのイテレータであり、必要に応じて要素を生成する | walkdir |

### 計算ロジック

readdir は OS からのエントリ一覧を取得後、sort=true の場合は Julia の sort! でアルファベット順にソートする。walkdir は深さ優先探索で再帰的にディレクトリを走査する。

## データベース操作仕様

### 操作別データベース影響一覧

該当なし。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| IOError | SystemError | ディレクトリが存在しない | パスの存在確認 |
| IOError | SystemError | ディレクトリの読み取り権限がない | chmod で権限変更 |
| IOError | SystemError | walkdir 中にディレクトリが削除された | onerror コールバックで処理 |

### リトライ仕様

一般にリトライは不要。walkdir で onerror コールバックを使用して個別ディレクトリのエラーを無視しつつ走査を継続することが可能。

## トランザクション仕様

該当なし。ディレクトリの読み取りは読み取り専用操作。

## パフォーマンス要件

- readdir は単一のシステムコールでディレクトリ内容を取得するため高速
- walkdir は遅延評価により、巨大なディレクトリツリーでもメモリ消費を抑えられる
- sort=false オプションでソートコストを回避可能

## セキュリティ考慮事項

- ディレクトリの内容はファイルシステムのパーミッションに従って制限される
- follow_symlinks=true の場合、シンボリックリンクループに陥る可能性がある（walkdir はループ検出機構を持たない場合がある）

## 備考

- readdir の結果にはファイルの種別情報が含まれないため、isfile/isdir で別途判定が必要
- walkdir は Python の `os.walk` に相当する機能
- walkdir は Channel（コルーチン）を使った遅延イテレータとして実装されている

---

## コードリーディングガイド

本機能を理解するために参照すべきファイルと、推奨する読み解き順序を以下に示す。

### 推奨読解順序

#### Step 1: データ構造を理解する

ディレクトリ走査は文字列の配列とタプルを主なデータ構造とする。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | file.jl | `base/file.jl` | readdir の戻り値型 `Vector{String}` を理解する |
| 1-2 | file.jl | `base/file.jl` | walkdir が yield する `(root, dirs, files)` タプルの構造を理解する |

**読解のコツ**: walkdir は Channel を使ったイテレータパターンで実装されている。Julia の Channel と Task の基本概念を理解しておくとよい。

#### Step 2: エントリーポイントを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | file.jl | `base/file.jl` | `readdir(dir)` - ディレクトリ内容の読み取り。ccall で `uv_fs_scandir` 系を呼び出す |
| 2-2 | file.jl | `base/file.jl` | `walkdir(dir)` - 再帰走査。Channel ベースのコルーチンで実装 |

**主要処理フロー**:
1. `readdir`: `uv_fs_scandir` でエントリ取得 → ソート → join オプション処理 → 返却
2. `walkdir`: Channel 生成 → readdir で各ディレクトリの内容取得 → dirs/files に分類 → yield → サブディレクトリに再帰

#### Step 3: walkdir の再帰処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | file.jl | `base/file.jl` | walkdir 内部の `_walkdir` 再帰関数。topdown フラグによる yield タイミングの制御 |

### プログラム呼び出し階層図

```
readdir(dir; join=false, sort=true)
    ├─ ccall(uv_fs_scandir系) ... OS からエントリ取得
    ├─ sort ? sort!(entries) : entries
    └─ join ? joinpath.(dir, entries) : entries

walkdir(dir; topdown=true, follow_symlinks=false, onerror=throw)
    └─ Channel() do chnl
        └─ _walkdir(chnl, dir)
            ├─ readdir(dir)
            ├─ 分類: dirs[], files[]
            ├─ topdown ? put!(chnl, (dir, dirs, files)) : nothing
            ├─ for subdir in dirs
            │      └─ _walkdir(chnl, joinpath(dir, subdir))  [再帰]
            └─ !topdown ? put!(chnl, (dir, dirs, files)) : nothing
```

### データフロー図

```
[入力]                [処理]                              [出力]

ディレクトリ ──────▶ readdir ─▶ scandir + sort    ──────▶ Vector{String}
ディレクトリ ──────▶ walkdir ─▶ 再帰 readdir      ──────▶ Iterator{(root, dirs, files)}
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| file.jl | `base/file.jl` | ソース | readdir, walkdir の定義 |
| path.jl | `base/path.jl` | ソース | joinpath（join オプション時のパス結合） |
| stat.jl | `base/stat.jl` | ソース | isdir/isfile（walkdir での種別判定） |
| channels.jl | `base/channels.jl` | ソース | Channel（walkdir のイテレータ基盤） |
