[C++] filesystemクラスの使い方 – ファイル操作の効率化
C++17で導入されたstd::filesystem
は、ファイルやディレクトリ操作を効率化するための標準ライブラリです。
これにより、ファイルの存在確認、コピー、削除、ディレクトリの作成、パス操作などが簡単に行えます。
例えば、std::filesystem::exists
でファイルの存在を確認し、std::filesystem::copy
でファイルをコピーできます。
これらはOS依存のコードを抽象化し、移植性を向上させます。
filesystemクラスとは
C++17から追加されたfilesystem
クラスは、ファイルシステムに関連する操作を簡単に行うためのライブラリです。
このクラスを使用することで、ファイルやディレクトリの作成、削除、移動、コピー、パスの操作などが効率的に行えます。
従来のC++では、ファイル操作は標準ライブラリの<fstream>
や<cstdio>
を使用して行っていましたが、filesystem
クラスを使うことで、より直感的で簡潔なコードを書くことが可能になります。
filesystem
クラスは、以下のような機能を提供しています:
- ファイルやディレクトリの存在確認
- ファイルのコピーや移動
- ディレクトリの作成や削除
- パスの操作(結合、正規化など)
このクラスを利用することで、ファイル操作の効率化が図れ、コードの可読性も向上します。
次のセクションでは、filesystem
クラスの基本的な使い方について詳しく解説します。
filesystemクラスの基本的な使い方
filesystem
クラスを使用するためには、まず<filesystem>
ヘッダーファイルをインクルードする必要があります。
以下に、基本的な使い方を示すサンプルコードを紹介します。
このコードでは、ディレクトリの作成、ファイルの存在確認、パスの表示を行います。
#include <iostream>
#include <filesystem> // filesystemライブラリをインクルード
namespace fs = std::filesystem; // 名前空間を短縮
int main() {
// 新しいディレクトリを作成
fs::path dirPath("example_directory");
if (fs::create_directory(dirPath)) {
std::cout << "ディレクトリを作成しました: " << dirPath << std::endl;
} else {
std::cout << "ディレクトリの作成に失敗しました: " << dirPath << std::endl;
}
// ファイルの存在確認
fs::path filePath("example_file.txt");
if (fs::exists(filePath)) {
std::cout << "ファイルは存在します: " << filePath << std::endl;
} else {
std::cout << "ファイルは存在しません: " << filePath << std::endl;
}
// パスの表示
std::cout << "ディレクトリのパス: " << fs::absolute(dirPath) << std::endl;
return 0;
}
ディレクトリを作成しました: example_directory
ファイルは存在しません: example_file.txt
ディレクトリのパス: /path/to/current/directory/example_directory
このコードでは、以下の操作を行っています:
create_directory
関数を使用して、新しいディレクトリを作成します。exists
関数を使用して、指定したファイルが存在するかどうかを確認します。absolute
関数を使用して、ディレクトリの絶対パスを表示します。
これにより、filesystem
クラスの基本的な機能を理解することができます。
次のセクションでは、ファイル操作について詳しく解説します。
ファイル操作
filesystem
クラスを使用すると、ファイルの作成、コピー、移動、削除などの操作が簡単に行えます。
以下に、これらの基本的なファイル操作を示すサンプルコードを紹介します。
このコードでは、ファイルの作成、コピー、移動、削除を行います。
#include <iostream>
#include <filesystem> // filesystemライブラリをインクルード
#include <fstream> // fstreamライブラリをインクルード
namespace fs = std::filesystem; // 名前空間を短縮
int main() {
// 新しいファイルを作成
fs::path filePath("example_file.txt");
std::ofstream file(filePath);
if (file) {
file << "これはサンプルファイルです。\n"; // ファイルにテキストを書き込む
file.close();
std::cout << "ファイルを作成しました: " << filePath << std::endl;
} else {
std::cout << "ファイルの作成に失敗しました: " << filePath << std::endl;
}
// ファイルのコピー
fs::path copyPath("example_file_copy.txt");
fs::copy(filePath, copyPath);
std::cout << "ファイルをコピーしました: " << copyPath << std::endl;
// ファイルの移動
fs::path movePath("moved_example_file.txt");
fs::rename(filePath, movePath);
std::cout << "ファイルを移動しました: " << movePath << std::endl;
// ファイルの削除
fs::remove(copyPath);
std::cout << "コピーしたファイルを削除しました: " << copyPath << std::endl;
return 0;
}
ファイルを作成しました: example_file.txt
ファイルをコピーしました: example_file_copy.txt
ファイルを移動しました: moved_example_file.txt
コピーしたファイルを削除しました: example_file_copy.txt
このコードでは、以下の操作を行っています:
ofstream
を使用して、新しいファイルを作成し、テキストを書き込みます。copy
関数を使用して、元のファイルをコピーします。rename
関数を使用して、ファイルを新しい名前に変更(移動)します。remove
関数を使用して、コピーしたファイルを削除します。
これにより、filesystem
クラスを使用したファイル操作の基本を理解することができます。
次のセクションでは、ディレクトリ操作について詳しく解説します。
ディレクトリ操作
filesystem
クラスを使用すると、ディレクトリの作成、削除、内容の列挙などの操作が簡単に行えます。
以下に、これらの基本的なディレクトリ操作を示すサンプルコードを紹介します。
このコードでは、ディレクトリの作成、削除、ディレクトリ内のファイルの列挙を行います。
#include <iostream>
#include <filesystem> // filesystemライブラリをインクルード
namespace fs = std::filesystem; // 名前空間を短縮
int main() {
// 新しいディレクトリを作成
fs::path dirPath("example_directory");
if (fs::create_directory(dirPath)) {
std::cout << "ディレクトリを作成しました: " << dirPath << std::endl;
} else {
std::cout << "ディレクトリの作成に失敗しました: " << dirPath << std::endl;
}
// ディレクトリ内のファイルを列挙
std::cout << "ディレクトリ内のファイル:\n";
for (const auto& entry : fs::directory_iterator(dirPath)) {
std::cout << " - " << entry.path().filename() << std::endl;
}
// ディレクトリの削除
if (fs::remove(dirPath)) {
std::cout << "ディレクトリを削除しました: " << dirPath << std::endl;
} else {
std::cout << "ディレクトリの削除に失敗しました: " << dirPath << std::endl;
}
return 0;
}
ディレクトリを作成しました: example_directory
ディレクトリ内のファイル:
ディレクトリを削除しました: example_directory
このコードでは、以下の操作を行っています:
create_directory
関数を使用して、新しいディレクトリを作成します。directory_iterator
を使用して、指定したディレクトリ内のファイルを列挙します。remove
関数を使用して、作成したディレクトリを削除します。
これにより、filesystem
クラスを使用したディレクトリ操作の基本を理解することができます。
次のセクションでは、パス操作について詳しく解説します。
パス操作
filesystem
クラスでは、ファイルやディレクトリのパスを操作するための便利な機能が提供されています。
パスの結合、正規化、拡張子の取得などが簡単に行えます。
以下に、これらの基本的なパス操作を示すサンプルコードを紹介します。
このコードでは、パスの結合、拡張子の取得、親ディレクトリの取得を行います。
#include <iostream>
#include <filesystem> // filesystemライブラリをインクルード
namespace fs = std::filesystem; // 名前空間を短縮
int main() {
// 基本のパスを定義
fs::path basePath("example_directory");
// パスの結合
fs::path filePath = basePath / "example_file.txt";
std::cout << "結合したパス: " << filePath << std::endl;
// 拡張子の取得
fs::path fileExtension = filePath.extension();
std::cout << "ファイルの拡張子: " << fileExtension << std::endl;
// 親ディレクトリの取得
fs::path parentPath = filePath.parent_path();
std::cout << "親ディレクトリのパス: " << parentPath << std::endl;
return 0;
}
結合したパス: example_directory/example_file.txt
ファイルの拡張子: .txt
親ディレクトリのパス: example_directory
このコードでは、以下の操作を行っています:
/
演算子を使用して、基本のパスとファイル名を結合します。extension
関数を使用して、ファイルの拡張子を取得します。parent_path
関数を使用して、ファイルの親ディレクトリのパスを取得します。
これにより、filesystem
クラスを使用したパス操作の基本を理解することができます。
次のセクションでは、エラーハンドリングと例外について詳しく解説します。
エラーハンドリングと例外
filesystem
クラスを使用する際には、ファイルやディレクトリの操作中に発生する可能性のあるエラーや例外を適切に処理することが重要です。
filesystem
ライブラリでは、操作が失敗した場合に例外をスローすることがあります。
これにより、エラーの原因を特定し、適切な対処を行うことができます。
以下に、エラーハンドリングの基本的な方法を示すサンプルコードを紹介します。
#include <iostream>
#include <filesystem> // filesystemライブラリをインクルード
namespace fs = std::filesystem; // 名前空間を短縮
int main() {
fs::path dirPath("non_existent_directory"); // 存在しないディレクトリのパス
try {
// 存在しないディレクトリを削除しようとする
fs::remove(dirPath);
} catch (const fs::filesystem_error& e) {
// 例外が発生した場合の処理
std::cout << "エラー: " << e.what() << std::endl;
std::cout << "エラーコード: " << e.code() << std::endl;
}
return 0;
}
エラー: non_existent_directory: No such file or directory
エラーコード: 2
このコードでは、以下の操作を行っています:
- 存在しないディレクトリを削除しようとすることで、
filesystem_error
例外を発生させます。 try-catch
ブロックを使用して、例外をキャッチし、エラーメッセージとエラーコードを表示します。
このように、filesystem
クラスを使用する際には、エラーハンドリングを適切に行うことで、プログラムの安定性を向上させることができます。
次のセクションでは、応用的な使い方について詳しく解説します。
応用的な使い方
filesystem
クラスは、基本的なファイルやディレクトリの操作だけでなく、より複雑なシナリオにも対応できます。
ここでは、いくつかの応用的な使い方を示すサンプルコードを紹介します。
具体的には、ディレクトリ内のすべてのファイルをコピーする方法と、特定の拡張子を持つファイルを検索する方法を解説します。
ディレクトリ内のすべてのファイルをコピーする
以下のコードでは、指定したディレクトリ内のすべてのファイルを別のディレクトリにコピーします。
#include <iostream>
#include <filesystem> // filesystemライブラリをインクルード
namespace fs = std::filesystem; // 名前空間を短縮
int main() {
fs::path sourceDir("source_directory"); // コピー元のディレクトリ
fs::path destDir("destination_directory"); // コピー先のディレクトリ
// コピー先のディレクトリを作成
fs::create_directory(destDir);
// ディレクトリ内のすべてのファイルをコピー
for (const auto& entry : fs::directory_iterator(sourceDir)) {
if (fs::is_regular_file(entry)) { // 通常のファイルか確認
fs::copy(entry.path(), destDir / entry.path().filename());
std::cout << "コピーしました: " << entry.path() << std::endl;
}
}
return 0;
}
コピーしました: source_directory/example_file1.txt
コピーしました: source_directory/example_file2.txt
特定の拡張子を持つファイルを検索する
次のコードでは、指定したディレクトリ内で特定の拡張子(例:.txt
)を持つファイルを検索し、そのパスを表示します。
#include <iostream>
#include <filesystem> // filesystemライブラリをインクルード
namespace fs = std::filesystem; // 名前空間を短縮
int main() {
fs::path searchDir("search_directory"); // 検索対象のディレクトリ
std::string extension = ".txt"; // 検索する拡張子
std::cout << "拡張子 " << extension << " のファイル:\n";
for (const auto& entry : fs::recursive_directory_iterator(searchDir)) {
if (entry.path().extension() == extension) { // 拡張子が一致するか確認
std::cout << " - " << entry.path() << std::endl;
}
}
return 0;
}
拡張子 .txt のファイル:
- search_directory/example_file1.txt
- search_directory/subdirectory/example_file2.txt
これらのコード例では、filesystem
クラスの強力な機能を活用して、ディレクトリ内のファイルを効率的に操作する方法を示しています。
これにより、ファイルシステムに対する高度な操作が可能となり、プログラムの柔軟性が向上します。
まとめ
この記事では、C++のfilesystem
クラスを使用したファイルやディレクトリの操作について詳しく解説しました。
基本的な使い方から応用的なシナリオまで、さまざまな機能を紹介し、実際のコード例を通じてその利便性を強調しました。
これを機に、filesystem
クラスを活用して、より効率的で直感的なファイル操作を行ってみてください。