Shoeisha Technology Media

CodeZine(コードジン)

記事種別から探す

Visual C++ 2017で一足お先にfilesystem

  • LINEで送る
  • このエントリーをはてなブックマークに追加
2017/05/16 14:00

 Visual Studio 2017がリリースされました、Visual Studio 20周年おめでとうございます。早速RC版からupdateし、変更点の確認ついでに目新しいヘッダが追加されてはいないかとsystem-includeディレクトリを眺めていたら<filesystem>が目に留まりました。filesystemはVC++2015にも入ってたんですが、紹介するのをコロッと忘れてましたよ。ファイルとディレクトリの操作にとっても便利なfilesystemを紹介いたします。

目次

filesystemの概要

 filesystemはBoostに収録されたライブラリ:boost.filesystemをベースとし、今年末までには決まるはずの標準規格:C++17の一部となる予定。まだ仕様が確定していないので、Visual C++ 2015/2017に見つけたfilesystemは実験的(experimental)な実装であり、クラスや関数は名前空間:std::experimental::filesystemに置かれています。

 filesystemのイケてるところをお見せするため、「カレント・ディレクトリ配下のファイル/ディレクトリを再帰的に列挙する」コードを書きました。

 まずはWin32-API版。

list-01n walk_dir_recursive_win32.cpp
#undef UNICODE
#include <Windows.h>
#include <iostream>
#include <string>

void walk_dir_recursive(const std::string& dir) {
  WIN32_FIND_DATA data;
  // 最初のエントリを探す(結果はdataに格納される)
  HANDLE handle = FindFirstFile((dir + "\\*.*").c_str(), &data);
  while ( handle != INVALID_HANDLE_VALUE ) {
    std::string filename = data.cFileName;
    if (filename != "." && filename != "..") { // . と .. は除外して
      filename = dir + "\\" + filename;
      // そのエントリがディレクトリなら 
      if ( data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) {
        std::cout << "dir. " << filename << std::endl;
        walk_dir_recursive(filename); // さらに深く潜る
      } else {
        std::cout << "file " << filename << std::endl;
      }
    }
    // 次のエントリを探す。なかったらCloseしてwhile-loopを抜ける。
    if ( !FindNextFile(handle, &data) ) {
      FindClose(handle);
      handle = INVALID_HANDLE_VALUE;
    }
  }
}

int main() {
  // カレント・ディレクトリから列挙開始
  char current[260];
  GetCurrentDirectory(260, current);
  walk_dir_recursive(current);
}

 FindFirstFile()でエントリの最初の一つを手に入れ、次のエントリを取り出すFindNextFile()を繰り返し、FindClose()で終了。取り出したエントリがディレクトリなら再帰的に呼び出してます、そこそこメンド臭いですね。こんな実行結果が得られます。

 かたやfilesystemを使うと:

list-02 walk_dir_recursive_filesystem.cpp
#include <filesystem>
#include <iostream>

namespace fs = std::experimental::filesystem;

void walk_dir_recursive(const fs::path& dir) {
  for ( auto ent : fs::recursive_directory_iterator(dir) ) {
    std::cout << (fs::is_directory(ent) ? "dir. " : "file ")
              << ent << std::endl;
  }
}

int main() {
  // カレント・ディレクトリから列挙開始
  walk_dir_recursive(fs::current_path());
}

 たったこれだけでWin32版と同じ結果が得られます。


  • LINEで送る
  • このエントリーをはてなブックマークに追加

著者プロフィール

  • επιστημη(エピステーメー)

    C++に首まで浸かったプログラマ。 Microsoft MVP, Visual C++ (2004.01~) だったり わんくま同盟でたまにセッションスピーカやったり 中国茶淹れてにわか茶人を気取ってたり、 あと Facebook とか。 著書: - STL標準講座 (監修) -...

All contents copyright © 2005-2017 Shoeisha Co., Ltd. All rights reserved. ver.1.5