HOWTO · C++
C++ でファイルが存在するかどうかを確認する方法
この記事では、ディレクトリ内にファイルが存在するかどうかを確認する方法をいくつか紹介します。
このページの内容
std::filesystem::exists は、パスがファイルシステム上の項目を指しているかどうかを調べます。ファイルにもディレクトリにも true を返します。以下の例では、小さな一時ディレクトリとファイルを作成し、確認対象を自前で用意します。プログラムで調べたいパスに合わせて file を置き換えてください。
std::filesystem::exists でディレクトリ内のファイルを確認する
次の例を実行します。
#include <chrono>
#include <filesystem>
#include <fstream>
#include <iostream>
#include <string>
int main() {
namespace fs = std::filesystem;
const auto unique = std::chrono::steady_clock::now().time_since_epoch().count();
const fs::path folder = fs::temp_directory_path() /
("cpp-exists-" + std::to_string(unique));
std::error_code ec;
if (!fs::create_directory(folder, ec) || ec) {
std::cout << "Could not prepare example\n";
return 1;
}
struct cleanup_guard {
fs::path path;
~cleanup_guard() {
std::error_code cleanup_error;
fs::remove_all(path, cleanup_error);
}
} cleanup{folder};
const fs::path file = folder / "notes.txt";
{
std::ofstream output(file);
if (!output) {
std::cout << "Could not prepare example\n";
return 1;
}
}
std::cout << (fs::exists(file) ? "Path exists\n" : "Path does not exist\n");
std::cout << (fs::is_regular_file(file) ? "It is a regular file\n"
: "It is not a regular file\n");
}
Path exists
It is a regular file
fs::exists(file) は、渡されたパスを確認します。一致するファイル名を検索するわけではありません。ここでは folder / "notes.txt" によって、std::filesystem::path を使って指定したディレクトリとファイル名を結合しています。この型が、使用するプラットフォームに応じたパス区切り文字を処理します。対象がプロセスの現在の作業ディレクトリ外にある場合は、同じ方法で実際のディレクトリパスと結合してください。
"notes.txt" のような相対パスは、プログラムの起動環境によって設定されるプロセスの現在の作業ディレクトリを基準に解決されます。実行ファイルが置かれたディレクトリを基準に自動で解決されるわけではありません。現在の作業ディレクトリを確認するには fs::current_path() を呼び出します。プロセスの作業ディレクトリを変更するには fs::current_path(path) を使い、報告されたファイルシステムエラーを処理してください。確認したい場所が一つだけなら、既知のディレクトリからパスを組み立てるほうが通常は明確です。
exists が答えるのは項目が存在するかどうかであり、その種類ではありません。通常ファイルだけを対象にする場合は fs::is_regular_file(path) を、ディレクトリを想定する場合は fs::is_directory(path) を使います。プログラムにファイルシステムへのアクセス権がない場合や、確認中にパスの状態が変わった場合は、これらの関数で有効な結果を得られないこともあります。そうした状況を区別する必要があるコードでは、std::error_code を受け取るオーバーロードを使い、返された真偽値とは別にエラーを確認してください。
たとえば std::error_code ec; const bool found = fs::exists(path, ec); のようにすると、found と ec の両方を調べられます。エラーがなく false が返った場合はパスが見つからず、エラーが設定されている場合は確認を完了できなかった理由を表します。エラーコード引数を取らないオーバーロードは、ファイルシステムエラーを例外として報告します。想定されるファイルシステムの問題があっても処理を続ける必要があるコードではエラーコード形式を選び、単純な確認を読みやすく保ちたい場合は例外を送出する形式を使えます。また、確認してから開くまでの間にパスが別の項目を指すようになる可能性もあります。そのため、確認結果は検索時点での答えとして扱い、後続の操作が必ず成功する保証とは考えないでください。
この例は std::filesystem を使い、一時的なテスト用データを自分で作成します。ディレクトリやファイルの準備に失敗すると、準備に関するメッセージを表示してゼロ以外のステータスで終了します。後始末用のガードは通常の終了時に一時ディレクトリの削除を試み、削除時のエラーは無視します。確認処理には例外を送出するオーバーロードを使っているため、捕捉されないファイルシステム例外が main の外へ伝播すると、ガードのデストラクターが実行される保証はなく、プログラムが終了することがあります。正常に処理された場合は、上に示した2行が出力されます。出力に含まれるラベルはコードと同じく英語のままです。