【C++】ファイルの基本操作
C++でのWindows環境のファイル操作はWinAPIを使うのがデフォルトでしたがC++17からはfilesystemのライブラリが標準で組み込まれました。(標準なんでLinuxやMacでも使えるのかな?)
これによりファイルのコピーや移動、削除、ファイルパスの取り扱い操作などが簡単にできます。今回はこのfilesystemでよく使いそうなメソッドのみを紹介していきたいと思います。
環境はWindows10 Visual Studioのデバッグモードで、デフォルトの実行階層はソースが配置されている場所となります。
もしVisual Studioでfilesystemのライブラリが使用できない場合こちらを参考にC++17を有効化しておきましょう。
アプリケーションの実行階層を取得
アプリケーションの実行階層を取得するにはcurrent_path関数を使用します。
#include <filesystem> #include <iostream> void main() { std::filesystem::path path = std::filesystem::current_path(); std::cout << path.string() << std::endl; system("pause"); }
C:\Users\ユーザ名\source\repos\Test\Test
※system(“pause”);は実行結果が見やすいように入れています。
相対パスを絶対パスに変換
相対パスを絶対パスに変換するにはabsolute関数を使用します。
#include <filesystem> #include <iostream> void main() { std::filesystem::path result = std::filesystem::absolute("./test.txt"); std::cout << result.string() << std::endl; system("pause"); }
C:\Users\ユーザ名\source\repos\Test\Test\test.txt
指定階層の親階層を取得する
#include <filesystem> #include <iostream> void main() { std::filesystem::path path = std::filesystem::current_path(); std::filesystem::path parent = path.parent_path(); std::cout << std::filesystem::absolute(parent).string() << std::endl; system("pause"); }
C:\Users\ユーザー名\source\repos\Test
ファイル、フォルダなどが存在するか
指定パスにエンティティが存在するかどうかはexists関数を使用します。
#include <filesystem> #include <iostream> void main() { bool isExists = std::filesystem::exists("./test.txt"); std::cout << (isExists ? "true" : "false") << std::endl; system("pause"); }
true
ファイルかフォルダかを判定する
is~関数で、そのエンティティが何なのかを判定できます。
is_directoryでフォルダかどうかを判定できます。
#include <filesystem> #include <iostream> void main() { bool isDirectory = std::filesystem::is_directory("./test.txt"); std::cout << (isDirectory ? "true" : "false") << std::endl; system("pause"); }
false
is_regular_fileでファイルかどうかを判定できます。
#include <filesystem> #include <iostream> void main() { bool isFile = std::filesystem::is_regular_file("./test.txt"); std::cout << (isFile ? "true" : "false") << std::endl; system("pause"); }
true
※ちなみにis_symlinkなどのシンボリックリンクを判定するものも存在します。
シンボリックリンク以外もありますので、詳細を知りたい方はこちらのサイトで勉強するのが得策です。
ファイル、フォルダなどをコピーする
ファイルやフォルダをコピーする場合はcopy(コピー元のパス, コピー先のパス,[コピーオプション])関数を利用します。
下記のプログラムを実行します。
#include <filesystem> std::filesystem::copy("./test.txt", "./test2.txt"); }
もしフォルダの中を再帰的に走査してコピーしたい場合はコピーオプションにrecursiveを指定します。windowsでフォルダコピーしたときと同じような動作をしますので、こちらのほうが一般的でしょう。
#include <filesystem> std::filesystem::copy("./test", "./test2",std::filesystem::copy_options::recursive); }
ファイル、フォルダなどを移動、または名前を変更
ファイルの移動、ファイル名の変更などはrename関数を使用します。
まずはファイル名を変更してみます。実行フォルダにtest2.txtファイルを配置しました。
test2.txtをtest3.txtにファイル名を変更してみます。
#include <filesystem> void main() { //test2.txtをtest3.txtに変更 std::filesystem::rename("./test2.txt", "./test3.txt"); }
次はファイルを移動してみます。実行フォルダにtest3.txtファイルとtestフォルダを配置し、test3.txtをtestフォルダに移動してみます。
#include <filesystem> void main() { //test3.txtをtestフォルダに移動 std::filesystem::rename("./test3.txt", "./test/test3.txt"); }
ファイル、フォルダを削除する
ファイル、フォルダを削除するにはremove関数を使用します。フォルダの中にファイルなどが存在する場合はエラーが発生します。
フォルダの中身も全部削除する場合はremove_all関数を使用します。
サンプルではtest.txtファイルとtestフォルダを削除してみます。(フォルダの中にはファイルが存在している状態です。)
#include <filesystem> void main() { //ファイル削除 std::filesystem::remove("./test.txt"); //ファイル削除(全階層) std::filesystem::remove_all("./test"); }
どちらも削除されました。
フォルダ作成
フォルダ作成はcreate_directory関数を使用します。
指定階層まで全フォルダを作成する場合はcreate_directories関数を使用します。
#include <filesystem> void main() { //フォルダ作成 std::filesystem::create_directory("./test3"); //フォルダ作成(全階層) std::filesystem::create_directories("./test3/inner/inin"); }
フォルダ3が作成されました。create_directoriesによりtest3にはさらにinnerフォルダ、ininフォルダが作成されているはずです。
フォルダの中身を取得する
フォルダの中身を取得するにはdirectory_iteratorを使用します。
全階層取得する場合はrecursive_directory_iteratorを使用します。
サンプルコードを試す際に使用するファイル構成は下記のイメージの通りとします。
#include <filesystem> #include <iostream> void main() { std::filesystem::directory_iterator e = std::filesystem::directory_iterator("./test"); for (auto f : e) { std::cout << f.path().string() << std::endl; } system("pause"); }
./test\test.txt
./test\test2.txt
./test\test3.txt
./test\testin
ついでにrecursive_directory_iteratorを使用したほうも試しておきましょう。
#include <filesystem> #include <iostream> void main() { std::filesystem::recursive_directory_iterator e = std::filesystem::recursive_directory_iterator("./test"); for (auto f : e) { std::cout << f.path().string() << std::endl; } system("pause"); }
./test\test.txt
./test\test2.txt
./test\test3.txt
./test\testin
./test\testin\test3.txt
しっかりフォルダの中のフォルダの中まで取得できていますね。
ディスカッション
コメント一覧
まだ、コメントがありません