Path と PathBuf
Rust には、ファイルやディレクトリのパス情報を扱うための std::path::Path struct が用意されています。
Path
の mutable 版(可変)である、std::path::PathBuf struct を使うと、パス情報を動的に組み立てていくことができます。
次の例では、パス形式の文字列リテラルから Path
と PathBuf
のインスタンスを生成しています。
use std::path::{Path, PathBuf};
fn main() {
let path = Path::new("/dir1/dir2/file.txt");
let path_buf = PathBuf::from("/dir1/dir2/file.txt");
println!("{:?}", path); //=> "/dir1/dir2/file.txt"
println!("{:?}", path_buf); //=> "/dir1/dir2/file.txt"
}
Path
や PathBuf
インスタンスから、パスを表現する文字列を取得したければ次のように記述できます。
let path = Path::new("/aaa/bbb/ccc");
let s = path.to_string_lossy();
assert_eq!(s, "/aaa/bbb/ccc");
ただ、実際のプロダクトコード内でパス情報を扱うときは、Path
オブジェクトのまま扱った方が都合がよいので、実際にこのような処理が必要になることはあまりありません。
例えば、ファイルを扱う std::fs モジュールの各種関数は、パスを表す文字列と Path
インスタンスのどちらも扱えるようになっています。
パスを分解する
Path
や PathBuf
の、次のようなメソッドを使うことで、/dir1/dir2/file.txt
のようなパス文字列から、親ディレクトリ名や、ベースネーム、拡張子名などを抽出することができます。
メソッド | 戻り値の型 | 意味 |
---|---|---|
Path#parent() | Option<&Path> | 親ディレクトリ |
Path#file_name() | Option<&OsStr> | ファイル名 |
Path#file_stem() | Option<&OsStr> | ベースネーム(ファイル名から拡張子を除いたもの) |
Path#extension() | Option<&OsStr> | 拡張子 |
拡張子が存在しない場合、Path#extension()
の戻り値は(Option
enum の)None
になります。
パスを構築する
パスを結合する
PathBuf
struct は、パスを動的に組み立てていくための push
、pop
、set_file_name
、set_extension
といったメソッドを備えています。
PathBuf::push
メソッドを連続して使うと、各階層のディレクトリ名、ファイル名を末尾に繋げていくことができます。
use std::path::PathBuf;
fn main() {
let mut path = PathBuf::new();
path.push("/");
path.push("aaa");
path.push("bbb");
path.push("ccc.txt");
assert_eq!(path, PathBuf::from("/aaa/bbb/ccc.txt"));
}
Path
struct は immutable(不変)なので、自分自身を変更する push
メソッドは備えていませんが、代わりに、パス結合後の結果を戻り値として返す Path#join
メソッドを備えています。
use std::path::{Path, PathBuf};
fn main() {
let path = Path::new("/aaa/bbb");
let path_buf = path.join("ccc.txt");
assert_eq!(path_buf, PathBuf::from("/aaa/bbb/ccc.txt"));
}
Path から PathBuf を生成する (to_path_buf)
Path#to_path_buf
メソッドを使うと、同一のパスを表す PathBuf
を生成することができます。
次の例では、Path
から PathBuf
を生成し、さまざまな編集メソッドを使って新しいパス情報を構築しています。
use std::path::{Path, PathBuf};
fn main() {
let path = Path::new("/aaa/bbb/ccc.txt");
let mut path_buf = path.to_path_buf(); // PathBuf を生成
path_buf.pop(); // 親ディレクトリへ ("/aaa/bbb")
path_buf.pop(); // 親ディレクトリへ ("/aaa")
path_buf.push("xxx"); // パスを結合 ("/aaa/xxx")
path_buf.push("yyy"); // パスを結合 ("/aaa/xxx/yyy")
path_buf.set_extension("txt"); // 拡張子をセット ("/aaa/xxx/yyy.txt")
assert_eq!(path_buf, PathBuf::from("/aaa/xxx/yyy.txt"));
}
ファイル名/拡張子を置換する (PathBuf::set_file_name, Path::with_file_name)
パスのファイル名部分だけを変更したいときは、PathBuf::set_file_name
メソッドを使います。
このメソッドは、パスの末尾がファイル名であるか、ディレクトリ名であるかは考慮しないので注意してください。
use std::path::PathBuf;
fn main() {
let mut path_buf = PathBuf::from("/aaa/bbb/ccc");
path_buf.set_file_name("XXX.txt");
assert_eq!(path_buf, PathBuf::from("/aaa/bbb/XXX.txt"));
}
ファイル名部分の置換には、Path::with_file_name
を使うこともできます。
Path
インスタンスは immutable(不変)なので、置換結果は戻り値として返されます。
use std::path::{Path, PathBuf};
fn main() {
let path = Path::new("/aaa/bbb/ccc");
let path_buf = path.with_file_name("XXX.txt");
assert_eq!(path_buf, PathBuf::from("/aaa/bbb/XXX.txt"));
}
同様に使えるメソッドとして、拡張子部分だけを置換する PathBuf::set_extension
や Path::with_extension
も用意されています。