Boost.Filesystem

ディレクトリを走査する必要が出たので Boost.Filesystem を利用する事にしました.Boost のビルドを行っていなかったので,ビルドから始めてサンプルプログラムを実行するまでのメモ.

Boost のビルド

ビルドは以下の 2 コマンドで終了します.

[boost_1_40_0]$ ./bootstrap.sh --prefix=/usr
[boost_1_40_0]$ ./bjam install

昔,Boost のビルドにもの凄く苦労した記憶があるのですが,随分と簡単になっているようです.bootstrap.bat と言うファイルが見えるので,Windows でも同様の方法でビルドできるのではないのかなと思います.

サンプルプログラム

手抜き ls.

#include <iostream>
#include <boost/filesystem.hpp>

int main(int argc, char* argv[]) {
    boost::filesystem::path dir = (argc <= 1) ?
        boost::filesystem::current_path() :
        boost::filesystem::path(argv[1]);
    
    // 絶対パスに変換する.
    std::cout << boost::filesystem::complete(dir).string() << std::endl;
    std::cout << std::endl;
    
    boost::filesystem::directory_iterator pos(dir);
    boost::filesystem::directory_iterator last;
    for (; pos != last; ++pos) {
        boost::filesystem::path p(*pos);
        if (boost::filesystem::is_directory(p)) {
            std::cout << p.leaf() << "/" << std::endl;
        }
        else std::cout << p.leaf() << std::endl;
    }
    
    return 0;
}

実行結果

必要なライブラリは,以下の 2 つのようです.

  • libboost_filesystem
  • libboost_system
[example]$ g++ -Wall ex_boost_filesystem.cpp -lboost_filesystem -lboost_system
[example]$ ./a c:/
c:/

$Recycle.Bin/
4e2f5954c6a8a4c049484d5a63b9c8/
99ee436e7432b337ad83/
b6d05b9d3141987ef6051fd0fe0cf6/
bin/
Boot/
bootmgr
BOOTSECT.BAK
code/
...

その他

boost::filesystem::fstream

引数に boost::filesystem::path を指定する事ができる,std::fstream(のラッパクラス)だそうです.

directory_iterator

ディレクトリを走査するイテレータには下記の 2 種類が存在するようです.

  • boost::filesystem::directory_iterator
  • boost::filesystem::recursive_directory_iterator

directory_iterator は現在の階層のみを走査し,recursive_directory_iterator はある要素がディレクトリだった場合にその中身も走査の対象とするイテレータです.recursive_directory_iterator深さ優先探索で指定されたディレクトリ以下全てのファイルを走査します.

recursive_directory_iterator には,no_push() と pop() と言うメソッドが用意されています.イテレータが指しているものがディレクトリの場合に no_push() を呼ぶと,そのディレクトリ以下のファイルは走査対象に含めなくなります.また,pop() を呼ぶと現在のディレクトリから抜けるようです.

path の各メソッドが返す文字列

boost::filesystem::path クラスには,root_path(), leaf() などのパスの一部分を返すメソッドが数多く用意されているので,それらのメソッドがどんな文字列を返すのかを調べてみました(実行結果は,Windows + cygwin での例).

[example]$ ./a ex_boost_filesystem2.cpp 
C:/code/cpp/example/ex_boost_filesystem2.cpp
-----
root_path       : C:/
root_name       : C:
root_directory  : /
relative_path   : code/cpp/example/ex_boost_filesystem2.cpp
leaf            : ex_boost_filesystem2.cpp
branch_path     : C:/code/cpp/example

string          : C:/code/cpp/example/ex_boost_filesystem2.cpp
file_string     : C:\code\cpp\example\ex_boost_filesystem2.cpp
directory_string: C:\code\cpp\example\ex_boost_filesystem2.cpp

使用したプログラムは,下記の通りです.

#include <iostream>
#include <boost/filesystem.hpp>

int main(int argc, char* argv[]) {
    boost::filesystem::path tmp = (argc <= 1) ?
        boost::filesystem::current_path() :
        boost::filesystem::path(argv[1]);
    boost::filesystem::path p = boost::filesystem::complete(tmp);
    
    std::cout << p.string() << std::endl;
    std::cout << "-----" << std::endl;
    std::cout << "root_path       : " << p.root_path().string() << std::endl;
    std::cout << "root_name       : " << p.root_name() << std::endl;
    std::cout << "root_directory  : " << p.root_directory() << std::endl;
    std::cout << "relative_path   : " << p.relative_path().string() << std::endl;
    std::cout << "leaf            : " << p.leaf() << std::endl;
    std::cout << "branch_path     : " << p.branch_path().string() << std::endl;
    std::cout << std::endl;
    std::cout << "string          : " << p.string() << std::endl;
    std::cout << "file_string     : " << p.file_string() << std::endl;
    std::cout << "directory_string: " << p.directory_string() << std::endl;
    
    return 0;
}