はじめに
Rustでファイルの一覧を表示させる簡単なコマンドラインツールを開発しました。
隠しファイルも含め全てのファイルを表示させます。
引数として受け取れるのはパスだけでオプションはありません。
使用例
ツール名はrls
にしました。
引数なしの場合はカレントディレクトリになります。
$ ./rls
.cargo-lock
.fingerprint
build
deps
examples
incremental
rls
rls.d
~
でホームディレクトリを指定できます
ファイル数が多いので一部省略しています。
$ ./rls ~/
.bash_history
.bash_logout
...
Videos
解説
実装した処理について簡単に解説します。
dirsクレートを使用
ホームディレクトリを取得するにはstd::env::home_dir
を使用すればよいですが、この関数は現在非推奨です。
warning: use of deprecated function `std::env::home_dir`: This function's behavior is unexpected and probably not what you want. Consider using a crate from crates.io instead.
代わりにdirs
クレートにあるdirs::home_dir
を使用します。
Cargo.toml
に以下を追記します。
[dependencies]
dirs = "4.0.0"
パスの文字列を解析する
パスの文字列を解析しPathBuf
として返す関数を追加します。
先頭が~
の場合はホームディレクトリのパスに置き換えます。
fn parse_path(path: &str) -> PathBuf {
if path.starts_with("~") {
let mut home_dir = dirs::home_dir().unwrap();
path[1..].split("/").for_each(|f| home_dir.push(f));
return home_dir;
}
PathBuf::from(path)
}
ファイルの一覧を取得する
指定したディレクトリ内のファイルの一覧を返す関数を追加します。
一覧をファイル名でソートしてから返します。
フォルダが見つからない、またはディレクトリ以外が指定されていた場合はエラーメッセージを返します。
fn get_dir_entries(dir: &PathBuf) -> Result<Vec<DirEntry>, String> {
if !dir.exists() {
let mes = format!("{} が見つかりませんでした。", dir.to_str().unwrap());
return Err(mes);
}
if !dir.is_dir() {
let mes = format!("{} はディレクトリではありません。", dir.to_str().unwrap());
return Err(mes);
}
let mut entries: Vec<DirEntry> = fs::read_dir(dir).unwrap().filter_map(|f| f.ok()).collect();
entries.sort_by_key(|e| e.file_name());
Ok(entries)
}
ファイル名を取得する
DirEntry
からファイル名を取得する関数を追加します。
OsString
をString
に変換します。
fn get_file_name(entry: &DirEntry) -> String {
entry.file_name().into_string().unwrap()
}
OsStringとは
プラットフォーム依存の文字列型です。
通常のString
はUTF-8ですがOsString
のエンコーディングはOSによって異なります。
公式のドキュメントによるとUnix系OSの場合はUTF-8で、Windowsの場合はUTF-16です。
コード
最後にコード全体を載せます。
コード
use dirs;
use std::{
env,
fs::{self, DirEntry},
path::PathBuf,
process,
};
fn parse_path(path: &str) -> PathBuf {
if path.starts_with("~") {
let mut home_dir = dirs::home_dir().unwrap();
path[1..].split("/").for_each(|f| home_dir.push(f));
return home_dir;
}
PathBuf::from(path)
}
fn get_dir_entries(dir: &PathBuf) -> Result<Vec<DirEntry>, String> {
if !dir.exists() {
let mes = format!("{} が見つかりませんでした。", dir.to_str().unwrap());
return Err(mes);
}
if !dir.is_dir() {
let mes = format!("{} はディレクトリではありません。", dir.to_str().unwrap());
return Err(mes);
}
let mut entries: Vec<DirEntry> = fs::read_dir(dir).unwrap().filter_map(|f| f.ok()).collect();
entries.sort_by_key(|e| e.file_name());
Ok(entries)
}
fn get_file_name(entry: &DirEntry) -> String {
entry.file_name().into_string().unwrap()
}
fn main() {
let args: Vec<String> = env::args().skip(1).collect();
let path = if args.len() == 0 { "." } else { &args[0] };
let dir = parse_path(path);
match get_dir_entries(&dir) {
Ok(entries) => {
entries
.iter()
.for_each(|e| println!("{}", get_file_name(e)));
}
Err(mes) => {
println!("{}", mes);
process::exit(1);
}
}
}
参考文献