ファイル/ディレクトリ操作には、Boost Filesystem Libraryを使用する。Boost Filesystem Libraryは、多くのプラットフォーム、コンパイラで動作する汎用的なファイル/ディレクトリ操作のライブラリである。このライブラリはビルドを必要する。
- エラーハンドリング
- ファイルをコピーする
- ファイルの削除
- ファイルを移動する/ファイル名を変更する
- ファイルが存在するかを調べる
- ファイルサイズを取得する
- ファイルの最終更新日時を取得する
- パスのファイル名を取得する
- パスの拡張子を取得する
- パスの拡張子を変更する
- ディレクトリを作成する
- ディレクトリ内のファイルを列挙する
- ディレクトリ内の全てのファイルを再帰的に列挙
- C++の国際標準規格上の類似する機能
Boost Filesystem Libraryのエラーハンドリングは、例外を投げるバージョン、エラーを参照で返すバージョンの2種類が存在する。
例外バージョン
何も指定しなければ、Boost Filesystem Libraryの関数でエラーが出た場合にはboost::filesystem::filesystem_error
例外が投げられる。
namespace fs = boost::filesystem;
try {
fs::foo();
}
catch (fs::filesystem_error& ex) {
std::cout << "エラー発生! : " << ex.what() << std::endl;
}
エラーを参照で返すバージョン
Boost Filesystem Libraryの最後の引数として、boost::system::error_code
の変数を渡せば、例外ではなく渡したエラー用変数にエラー情報が格納される。
namespace fs = boost::filesystem;
boost::system::error_code error;
fs::foo(error);
if (error) {
std::cout << "エラー発生! : " << error.message() << std::endl;
}
ファイルをコピーするには、boost::filesystem::copy_file()
関数を使用する。
- 第1引数はコピー元のパス
- 第2引数はコピー先のパス
コピーに失敗した場合は例外が投げられる。
#include <iostream>
#include <boost/filesystem.hpp>
namespace fs = boost::filesystem;
int main()
{
const fs::path path("dir1/a.txt"); // コピー元
const fs::path dest("dir2/a.txt"); // コピー先
try {
fs::copy_file(path, dest);
}
catch (fs::filesystem_error& ex) {
std::cout << ex.what() << std::endl;
throw;
}
}
上書きコピーをする場合は、copy_file()
関数に、boost::filesystem::copy_option::overwrite_if_exists
オプションを指定する。
#include <iostream>
#include <boost/filesystem.hpp>
namespace fs = boost::filesystem;
int main()
{
const fs::path path("dir1/a.txt");
const fs::path dest("dir2/a.txt");
try {
fs::copy_file(path, dest, fs::copy_option::overwrite_if_exists);
}
catch (fs::filesystem_error& ex) {
std::cout << ex.what() << std::endl;
throw;
}
}
ファイルを削除するには、boost::filesystem::remove()
を使用する。
#include <iostream>
#include <boost/filesystem.hpp>
namespace fs = boost::filesystem;
int main()
{
const fs::path path("dir1/a.txt");
try {
fs::remove(path);
}
catch (fs::filesystem_error& ex) {
std::cout << ex.what() << std::endl;
throw;
}
}
ファイルの移動、ファイル名の変更には、boost::filesystem::rename()
を使用する。
- 第1引数は、元となるファイルのパス。
- 第2引数は、移動先のファイルパス、もしくは新たなファイル名。
#include <iostream>
#include <boost/filesystem.hpp>
namespace fs = boost::filesystem;
int main()
{
const fs::path path("dir1/a.txt");
const fs::path dest("dir2/b.txt");
try {
fs::rename(path, dest);
}
catch (fs::filesystem_error& ex) {
std::cout << ex.what() << std::endl;
throw;
}
}
ファイルが存在するか調べるには、boost::filesystem::exists()
関数を使用する。
この関数は、ファイルが存在する場合はtrue
を返し、存在しない場合はfalse
を返す。
ファイルのステータス取得に失敗した場合はエラーを返す。
#include <iostream>
#include <boost/filesystem.hpp>
namespace fs = boost::filesystem;
int main()
{
const fs::path path("dir1/a.txt");
boost::system::error_code error;
const bool result = fs::exists(path, error);
if (!result || error) {
std::cout << "ファイルがない" << std::endl;
}
else {
std::cout << "ファイルがあった" << std::endl;
}
}
ファイルサイズを取得するには、boost::filesystem::file_size()
関数を使用する。
#include <iostream>
#include <boost/filesystem.hpp>
namespace fs = boost::filesystem;
int main()
{
const fs::path path("dir1/a.txt");
try {
const boost::uintmax_t size = fs::file_size(path);
std::cout << "ファイルサイズ: " << size << std::endl;
}
catch (fs::filesystem_error& ex) {
std::cout << ex.what() << std::endl;
throw;
}
}
実行結果の例:
ファイルサイズ: 5107200
ファイルの最終更新日時を取得するには、boost::filesystem::last_write_time()
関数を使用する。
この関数は戻り値として、std::time_t
型として日時を返す。
#include <iostream>
#include <boost/filesystem.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
namespace fs = boost::filesystem;
int main()
{
try {
const fs::path path("dir1/a.txt");
const std::time_t last_update = fs::last_write_time(path);
const boost::posix_time::ptime time = boost::posix_time::from_time_t(last_update);
std::cout << time << std::endl;
}
catch (fs::filesystem_error& ex) {
std::cout << "エラー発生! : " << ex.what() << std::endl;
}
}
実行結果の例:
2011-Mar-30 05:56:11
パスのファイル名を取得するには、boost::filesystem::path
クラスのfilename()
メンバ関数を使用する。
#include <iostream>
#include <boost/filesystem.hpp>
namespace fs = boost::filesystem;
int main()
{
fs::path p = "/a/b.txt";
fs::path filename = p.filename();
std::cout << filename.generic_string() << std::endl;
}
出力:
b.txt
パスの拡張子を取得するには、boost::filesystem::path
クラスのextension()
メンバ関数を使用する。この関数が返すパスは、ドット(.)を含む。
拡張子を持たないパスに対してこの関数を適用した場合は、空のパスが返る。
#include <iostream>
#include <boost/filesystem.hpp>
namespace fs = boost::filesystem;
int main()
{
fs::path p = "/a/b.txt";
fs::path extension = p.extension();
std::cout << extension.generic_string() << std::endl;
}
出力:
.txt
パスの拡張子を変更するには、boost::filesystem::path
クラスのreplace_extension()
メンバ関数を使用する。
#include <iostream>
#include <boost/filesystem.hpp>
namespace fs = boost::filesystem;
int main()
{
// 拡張子を.pngに変更する
// replace_extension()に指定する拡張子は、
// ドット(.)があってもなくても、どちらでもよい。
fs::path p = "/a.txt/b.txt";
p.replace_extension("png");
std::cout << p.generic_string() << std::endl;
}
出力:
/a.txt/b.png
ディレクトリを作成するには、boost::filesystem::create_directory()
関数を使用する。
第1引数として、ディレクトリのパスを指定する。
ネストしたディレクトリを一度に作ろうとした場合はエラーとなる。
#include <iostream>
#include <boost/filesystem.hpp>
namespace fs = boost::filesystem;
int main()
{
const fs::path path("dir");
boost::system::error_code error;
const bool result = fs::create_directory(path, error);
if (!result || error) {
std::cout << "ディレクトリの作成に失敗" << std::endl;
}
}
ネストしたディレクトリを含めて一度に作成するには、boost::filesystem::create_directories()
関数を使用する。
#include <iostream>
#include <boost/filesystem.hpp>
namespace fs = boost::filesystem;
int main()
{
const fs::path path("dir1/dir2");
boost::system::error_code error;
const bool result = fs::create_directories(path, error);
if (!result || error) {
std::cout << "ディレクトリの作成に失敗" << std::endl;
}
}
ディレクトリ内のファイルを列挙するには、boost::filesystem::directory_iterator
クラスを使用する。
#include <iostream>
#include <boost/filesystem.hpp>
#include <boost/foreach.hpp>
namespace fs = boost::filesystem;
int main()
{
const fs::path path("dir1");
BOOST_FOREACH(const fs::path& p, std::make_pair(fs::directory_iterator(path),
fs::directory_iterator())) {
if (!fs::is_directory(p))
std::cout << p.filename() << std::endl;
}
}
実行結果の例
"a.txt"
"b.png"
あるいは、上記の実装例の BOOST_FOREACH
部分は C++11 以降で range-based-for を使いたい場合、次のようにも書ける。
#include <iostream>
#include <boost/filesystem.hpp>
#include <boost/range/iterator_range.hpp>
namespace fs = boost::filesystem;
int main()
{
const fs::path path(".");
// この例の場合、 e は fs::path 型ではなく fs::directory_entry 型となる点に注意する。
for ( const auto& e : boost::make_iterator_range( fs::directory_iterator( path ), { } ) )
if ( ! fs::is_directory( e ) )
std::cout << e.path().filename() << std::endl;
}
実行結果の例は先の BOOST_FOREACH
バージョンと同様となるので省略する。
ディレクトリ内の全てのファイルを再帰的に列挙するには、boost::filesystem::recursive_directory_iterator
クラスを使用する。
#include <iostream>
#include <boost/filesystem.hpp>
#include <boost/foreach.hpp>
namespace fs = boost::filesystem;
int main()
{
const fs::path path("D:/boost_1_49_0/boost/filesystem");
BOOST_FOREACH(const fs::path& p, std::make_pair(fs::recursive_directory_iterator(path),
fs::recursive_directory_iterator())) {
if (!fs::is_directory(p))
std::cout << p << std::endl;
}
}
実行結果の例
"D:/boost_1_49_0/boost/filesystem\config.hpp"
"D:/boost_1_49_0/boost/filesystem\convenience.hpp"
"D:/boost_1_49_0/boost/filesystem\detail\utf8_codecvt_facet.hpp"
"D:/boost_1_49_0/boost/filesystem\exception.hpp"
"D:/boost_1_49_0/boost/filesystem\fstream.hpp"
"D:/boost_1_49_0/boost/filesystem\operations.hpp"
"D:/boost_1_49_0/boost/filesystem\path.hpp"
"D:/boost_1_49_0/boost/filesystem\v2\config.hpp"
"D:/boost_1_49_0/boost/filesystem\v2\convenience.hpp"
"D:/boost_1_49_0/boost/filesystem\v2\exception.hpp"
"D:/boost_1_49_0/boost/filesystem\v2\fstream.hpp"
"D:/boost_1_49_0/boost/filesystem\v2\operations.hpp"
"D:/boost_1_49_0/boost/filesystem\v2\path.hpp"
"D:/boost_1_49_0/boost/filesystem\v3\config.hpp"
"D:/boost_1_49_0/boost/filesystem\v3\convenience.hpp"
"D:/boost_1_49_0/boost/filesystem\v3\exception.hpp"
"D:/boost_1_49_0/boost/filesystem\v3\fstream.hpp"
"D:/boost_1_49_0/boost/filesystem\v3\operations.hpp"
"D:/boost_1_49_0/boost/filesystem\v3\path.hpp"
"D:/boost_1_49_0/boost/filesystem\v3\path_traits.hpp"