言語
日本語
English

Caution

お使いのブラウザはJavaScriptが無効になっております。
当サイトでは検索などの処理にJavaScriptを使用しています。
より快適にご利用頂くため、JavaScriptを有効にしたうえで当サイトを閲覧することをお勧めいたします。

Rust辞典

  1. トップページ
  2. Rust辞典
  3. std::path::Path / PathBuf

std::path::Path / PathBuf

対応: Rust 1.0(2015)

Rustのファイルパス操作には『std::path::Path』と『PathBuf』を使います。『Path』は借用された不変のパス参照、『PathBuf』は所有権を持つ可変のパスで、OS間のパス区切り文字の違いを自動的に吸収します。

構文

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

// Path — 不変のパス参照(&str のパス版)
let path = Path::new("/home/user/file.txt");

// PathBuf — 所有権を持つ可変のパス(String のパス版)
let mut buf = PathBuf::from("/home/user");
buf.push("documents"); // パスを追加します。
buf.push("file.txt");

// パスの結合(join は新しい PathBuf を返します)
let full = Path::new("/home").join("user").join("file.txt");

// パスの情報取得
path.file_name() // "file.txt"
path.file_stem() // "file"(拡張子なし)
path.extension() // "txt"
path.parent() // "/home/user"
path.exists() // ファイルの存在確認
path.is_file() // ファイルかどうか
path.is_dir() // ディレクトリかどうか

メソッド一覧

メソッド概要
Path::new(s)文字列から Path への参照を作成します。
PathBuf::from(s)文字列から PathBuf を作成します。
path.join(p)パスを結合した新しい PathBuf を返します。
buf.push(p)PathBuf にパスを追加します(可変操作)。
path.exists()パスが存在するかを確認します。bool を返します。
path.is_file()通常ファイルかどうかを確認します。
path.is_dir()ディレクトリかどうかを確認します。
path.file_name()ファイル名部分を Option<&OsStr> で返します。
path.file_stem()拡張子を除いたファイル名を返します。
path.extension()拡張子を Option<&OsStr> で返します。
path.parent()親ディレクトリを Option<&Path> で返します。
path.to_str()パスを &str に変換します(UTF-8 でない場合は None)。
path.display()表示用の文字列表現を返します(println! で使えます)。

サンプルコード

『Path』と『PathBuf』を使ったファイルパスの操作方法を確認するサンプルコードです。

sample_path_pathbuf.rs
use std::path::{Path, PathBuf};
use std::fs;

fn main() {
    // PathBuf でパスを組み立てます。
    let mut path = PathBuf::from("/home");
    path.push("user");
    path.push("documents");
    path.push("report.txt");
    println!("path: {}", path.display());
    // /home/user/documents/report.txt

    // join でパスを結合します(元のパスは変わりません)。
    let base = Path::new("/var/log");
    let app_log = base.join("myapp").join("error.log");
    println!("app_log: {}", app_log.display());
    // /var/log/myapp/error.log

    // パスの各部分を取得します。
    let file = Path::new("/home/user/documents/report.txt");
    println!("file_name: {:?}", file.file_name()); // "report.txt"
    println!("file_stem: {:?}", file.file_stem()); // "report"
    println!("extension: {:?}", file.extension()); // "txt"
    println!("parent: {:?}", file.parent()); // "/home/user/documents"

    // 存在確認と種類判定
    let current = Path::new(".");
    println!("カレントディレクトリ exists: {}", current.exists()); // true
    println!("is_dir: {}", current.is_dir()); // true
    println!("is_file: {}", current.is_file()); // false

    // &str への変換
    if let Some(s) = file.to_str() {
        println!("to_str: {}", s);
    }

    // テスト用ファイルを作って確認します。
    let test_path = Path::new("test_path.txt");
    fs::write(test_path, "test").unwrap();
    println!("test_path exists: {}", test_path.exists()); // true
    println!("test_path is_file: {}", test_path.is_file()); // true
    fs::remove_file(test_path).unwrap();

    // 拡張子の変更(PathBuf のみ)
    let mut p = PathBuf::from("archive.tar.gz");
    p.set_extension("bz2");
    println!("変更後: {}", p.display()); // archive.tar.bz2

    // Path からのコンポーネント取得
    for component in Path::new("/home/user/file.txt").components() {
        println!("component: {:?}", component);
    }
}

コンパイルして実行すると次のように出力されます。

rustc sample_path_pathbuf.rs
./sample_path_pathbuf
path: /home/user/documents/report.txt
app_log: /var/log/myapp/error.log
file_name: Some("report.txt")
file_stem: Some("report")
extension: Some("txt")
parent: Some("/home/user/documents")
カレントディレクトリ exists: true
is_dir: true
is_file: false
to_str: /home/user/documents/report.txt
test_path exists: true
test_path is_file: true
変更後: archive.tar.bz2
component: RootDir
component: Normal("home")
component: Normal("user")
component: Normal("file.txt")

よくあるミス

よくあるミス1: 文字列を直接連結してパスを作る

文字列を『/』で連結してパスを作ると、OSの区切り文字の違いや二重スラッシュの問題が発生します。

// NG: 文字列連結でパスを作る(Windowsで動かない・二重スラッシュになる可能性がある)
let path = "/home/".to_string() + "user/" + "file.txt";
// OK: PathBuf と push() / join() を使う
use std::path::PathBuf;

let mut path = PathBuf::from("/home");
path.push("user");
path.push("file.txt");
println!("{}", path.display()); // /home/user/file.txt

よくあるミス2: WindowsパスをUnix区切りで書く

Windowsでは区切り文字が『\』ですが、Rustの『Path』はOSに応じて自動的に適切な区切り文字を使います。バックスラッシュをハードコードする必要はありません。

use std::path::PathBuf;

// OK: join() を使えば OS を問わず正しい区切り文字が使われる
let path = PathBuf::from("C:\\Users").join("Kiryu").join("documents");
println!("{}", path.display());
// Windows: C:\Users\Kiryu\documents
// Unix:    C:\Users/Kiryu/documents(通常Unixではこの形式は使わない)

// より移植性の高い書き方
let home = PathBuf::from("/home");
let docs = home.join("kiryu").join("documents");
println!("{}", docs.display()); // /home/kiryu/documents

よくあるミス3: to_str() の戻り値を unwrap() する

『to_str()』はUTF-8として解釈できないパスの場合に『None』を返します。直接『unwrap()』すると非UTF-8パスでパニックします。

use std::path::Path;

// NG: UTF-8でないパスでパニックする可能性がある
let path = Path::new("/home/kiryu/file.txt");
let s = path.to_str().unwrap(); // 非UTF-8ならパニック
use std::path::Path;

// OK: Option で安全に処理する
let path = Path::new("/home/kiryu/file.txt");
match path.to_str() {
    Some(s) => println!("パス: {}", s),
    None => println!("UTF-8でないパスです"),
}

// または display() を使う(UTF-8以外も表示可能)
println!("{}", path.display());

概要

『Path』と『PathBuf』の関係は『&str』と『String』の関係と同じです。関数の引数では通常『&Path』か『impl AsRef<Path>』を受け取ることで、文字列リテラルや『PathBuf』など様々な型を受け入れられます。

Windows では区切り文字が『\』、Unix 系では『/』ですが、Rust の Path は OS に応じて自動的に適切な区切り文字を使うため、クロスプラットフォームのコードが書きやすくなっています。

ファイルの読み書きはstd::fs::read_to_string() / write()を、ファイルハンドルによる詳細な操作はFile::open() / File::create()を参照してください。

記事の間違いや著作権の侵害等ございましたらお手数ですがまでご連絡頂ければ幸いです。