理系学生日記

おまえはいつまで学生気分なのか

boost::filesystem::recursive_directory_iterator を使ってみると

Boost.Filesystem - Cube Lilac で boost::filesystem::recursive_directory_iterator が紹介されていたのですが、ぼくはこの存在を全く知りませんでした。
どのようなものかは上記エントリで非常に分かりやすく説明されていますが、ディレクトリを深さ優先探索で走査し、basic_directory_entry を次々に返すイテレータのようです。basic_directory_entry は path メソッドで basic_path クラスにアクセスできる。

どれだけの階層を辿ったかは、level メソッドでアクセスできるので、再帰的な ls みたいなことをしようとするとこんな感じでしょうか。

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

namespace fs = boost::filesystem;

std::string put_depth( int level ) {
  std::string ret;
  for ( int i = 0; i < level; i++ ) {
    ret += "  ";
  }
  return ret;
}
  
int main(int argc, char** argv) {

  std::string p( argc <= 1? "." : argv[1] );
  if ( fs::is_directory(p) ) {

    fs::recursive_directory_iterator last;
    for ( fs::recursive_directory_iterator itr(p); itr != last; ++itr ) {
      std::cout 
        << put_depth( itr.level() ) 
        << itr->path().filename() 
        << (fs::is_directory( itr->path() )? "/" : "")
        << std::endl;
    }
  }
  return 0;
}
mbp:~/work/test% g++ -Wall -lboost_filesystem-mt -lboost_system-mt recursive-ls.cpp 
mbp:~/work/test% ./a.out test-dir                                                  
a/
  a1
  a2
  a3
b/
  bb/
    bb1
    bb2
c/

pop() を使った例はこんな風になる。for 文を以下のように書き直す。

    for ( fs::recursive_directory_iterator itr(p); itr != last; ++itr ) {
      if ( itr->path().filename() == "bb" ) 
        itr.pop();
      
      std::cout 
        << put_depth( itr.level() ) 
        << itr->path().filename() 
        << (fs::is_directory( itr->path() )? "/" : "")
        << std::endl;
    }

これで実行すると、bb 以下のディレクトリは走査されない。

mbp:~/work/test% ./a.out test-dir                                                  
a/
  a1
  a2
  a3
b/
c/