Rust でディレクトリ内のファイルを列挙する (fs::read_dir)

read_dir 関数の基本

Rust の標準モジュール std::fsread_dir 関数 を使うと、ディレクトリ内のファイルやディレクトリを列挙することができます。

std::fs::read_dir 関数
pub fn read_dir<P: AsRef<Path>>(path: P) -> Result<ReadDir>

列挙結果には、カレントディレクトリ (.) や親ディレクトリ (..) は含まれないので、自然な列挙が可能です。

src/main.rs
use std::fs;

fn main() {
    let entries = fs::read_dir(".").unwrap(); // ReadDir を取得

    // ループで Result<DieEntry, Error> をひとつずつ処理
    for entry in entries {
        // DirEntry#file_name() でファイル名(ディレクトリ名)を取得できる
        println!("{:?}", entry.unwrap().file_name());
    }
}
実行結果
"Cargo.toml"
"target"
"Cargo.lock"
".gitignore"
".git"
"src"

エラーチェックする

上記ではコードを簡素化するために Result#unwrap メソッドを使っていますが、万が一 Err 値が返された場合は panic が発生してしまうので、プロダクトコードでは unwrap メソッドは使うべきではありません。 ResultOk 値を持っているかを調べつつ、その値を取り出すには、次のように if let 構文を使用できます。

他の実装例
use std::fs;

fn main() {
    if let Ok(entries) = fs::read_dir(".") {
        for entry in entries {
            if let Ok(entry) = entry {
                println!("{:?}", entry.file_name());
            }
        }
    }
}

Path インスタンスを取得する

DirEntry#file_name() でファイル名 (OsString) を取得する代わりに、DirEntry#path() を使って PathBuf オブジェクトを取得できます。 PathBuf は、パス情報を扱ういろいろなメソッドを提供しています。

let path = entry.path(); // PathBuf を取得

println!("file_name = {:?}", entry.file_name());
println!("is_file = {}", path.is_file());
println!("is_dir = {}", path.is_dir());
println!("is_absolute = {}", path.is_absolute());

ディレクトリ内のファイルリストを Vec で取得する

前述のように、Rust でディレクトリ内のファイルを列挙しようとすうと、少し面倒なコードになります。 下記のユーティリティ関数 read_dir_entries を使うと、指定したディレクトリに含まれているファイルやディレクトリの名前 (PathBuf) を Vec 形式でまとめて取得できます。

use std::{
    fs, io,
    path::{Path, PathBuf},
};

/** 指定したディレクトリ内のすべてのファイル(ディレクトリ)のパス情報を取得します。 */
fn read_dir_entries<P: AsRef<Path>>(path: P) -> io::Result<Vec<PathBuf>> {
    let mut entries = fs::read_dir(path)?
        .map(|res| res.map(|e| e.path()))
        .collect::<Result<Vec<_>, io::Error>>()?;

    entries.sort();
    Ok(entries)
}

fn main() {
    match read_dir_entries(".") {
        Ok(entries) => println!("{:?}", entries),
        Err(e) => eprintln!("ERROR: {}", e),
    }
}
実行結果
["./.git", "./.gitignore", "./Cargo.lock", "./Cargo.toml", "./src", "./target"]