C++のboost::filesystemでファイルやディレクトリを操作する

C++のboost::filesystemでファイルやディレクトリを操作する方法。

ファイルのコピー

#include <boost/filesystem/path.hpp>
#include <boost/filesystem/operations.hpp>

try {
  boost::filesystem::path src("C:\\sample\\src.txt");
  boost::filesystem::path dst("C:\\sample\\dst.txt");
  boost::filesystem::copy_file(src, dst);
} catch (std::exception& e) {
  std::cout << e.what() << std::endl;
}

ファイルの削除

#include <boost/filesystem/path.hpp>
#include <boost/filesystem/operations.hpp>

boost::filesystem::path src("C:\\sample\\src.txt");
if (boost::filesystem::remove(src)) {
  std::cout << "ok" << std::endl; //削除した
}

ファイル名の変更

#include <boost/filesystem/path.hpp>
#include <boost/filesystem/operations.hpp>

boost::filesystem::path src("C:\\sample\\src.txt");
boost::filesystem::path dst("C:\\sample\\dst.txt");
try{
  boost::filesystem::rename(src, dst);
} catch (std::exception& e) {
  std::cout << e.what() << std::endl;
}

ディレクトリの作成

#include <boost/filesystem/path.hpp>
#include <boost/filesystem/operations.hpp>

boost::filesystem::path dir("C:\\sample\\test");
if (boost::filesystem::create_directory(dir)) {
  std::cout << "ok" << std::endl; //ディレクトリの作成に成功した
}

ディレクトリの削除(ファイルの削除と同じ)

#include <boost/filesystem/path.hpp>
#include <boost/filesystem/operations.hpp>

boost::filesystem::path dir("C:\\sample\\test");
if (boost::filesystem::remove(dir)) {
  std::cout << "ok" << std::endl; //削除した
}

※ディレクトリが空でない時は削除に失敗する。次の「ディレクトリの内容の取得」でディレクトリを空にしてから削除すること。

ディレクトリの内容の取得

#include <boost/filesystem/path.hpp>
#include <boost/filesystem/operations.hpp>

boost::filesystem::path dir("C:\\sample");
boost::filesystem::directory_iterator end;
for (boost::filesystem::directory_iterator p(dir); p != end; ++p) {
  std::cout << p->leaf() << std::endl; //ファイル名
  std::cout << p->string() << std::endl; //フルパス
  if (boost::filesystem::is_directory(*p)) {  //ディレクトリの時
    std::cout << "<DIR>" << std::endl;
  }
}

フルパスからファイル名とパス名を取得する

#include <boost/filesystem/path.hpp>

boost::filesystem::path f("C:\\sample\\src.txt");
std::cout << f.leaf() << std::endl; //=> src.txt
std::cout << f.branch_path() << std::endl; //=> C:\sample

C++で一時ファイルを作成する

tmpfile()を使うと一時ファイルを作成することができます。
失敗した時はNULLを返します。

#include <stdio.h>

FILE* pf = tmpfile();
if (pf) { //ファイルの作成に成功した時
  fputs("tempfile", pf);
}
fclose(pf);

tmpnam()は一時ファイルのファイル名を作成します。

#include <stdio.h>

char* filename = tmpnam(NULL);
if (filename) {
  ofstream of(filename);

追記

Windows XPではtmpfile関数を使用するには管理者権限が必要になります。
現実問題としては、使い物になりません。

C++のstd::equalやstd::mismatchで指定範囲の要素を比較する

C++のstd::equalやstd::mismatchで指定範囲の要素を比較する

std::equalは指定した範囲をoperator==で比較します。

std::vector<std::string> vec1, vec2;
vec1.push_back("C++");
vec1.push_back("Java");
vec1.push_back("Python");

vec2.push_back("C++");
vec2.push_back("Java");
vec2.push_back("Python");

//vec1.begin()からvec1.end()までの範囲をoperator==で比較する
if (std::equal(vec1.begin(), vec1.end(), vec2.begin())) {
  std::cout << "equal" << std::endl;
} else {
  std::cout << "not equal" << std::endl;
}

std::equalの第4引数で、operator==の代わりに比較する関数を指定できます。

#include <algorithm>

//大文字小文字を区別しないで比較する
struct compare {
  bool operator()(const std::string& s1, const std::string& s2) {
    return (stricmp(s1.c_str(), s2.c_str()) == 0);
  }
};

std::vector<std::string> vec1, vec2;
vec1.push_back("C++");
vec1.push_back("Java");
vec1.push_back("Python");

vec2.push_back("c++");
vec2.push_back("java");
vec2.push_back("python");

if (std::equal(vec1.begin(), vec1.end(), vec2.begin(), compare())) {
  std::cout << "equal" << std::endl;
} else {
  std::cout << "not equal" << std::endl;
}

std::mismatchは2つのシーケンスの等しくない最初の要素を返します。

std::vector<std::string> vec1, vec2;
vec1.push_back("C++");
vec1.push_back("Java");
vec1.push_back("Python");

vec2.push_back("C++");
vec2.push_back("Java");
vec2.push_back("python");

std::pair<std::vector<std::string>::iterator, std::vector<std::string>::iterator> p = 
  std::mismatch(vec1.begin(), vec1.end(), vec2.begin());

std::cout << *(p.first) << std::endl; //Python
std::cout << *(p.second) << std::endl; //python

boost::splitで文字列を分割する

よくある文字列の分割処理は、boost::splitを使うと簡単です。

boost::splitの引数

boost::splitは3つの引数をとります。

  1. 出力シーケンス
  2. 入力コレクション
  3. 区切り文字を判断する述語

boost::splitで文字列をカンマで分割する

#include <iostream>
#include <string>
#include <boost/algorithm/string.hpp>
#include <boost/foreach.hpp>

std::string s = "abc,def,ghi,jkl"; //分割する文字列
std::list<std::string> results; //分割結果を格納する変数
boost::split(results, s, boost::is_any_of(",")); //,区切り

//分割結果を出力
BOOST_FOREACH(std::string p, results) {
  std::cout << p << std::endl;
}

複数の区切り文字で分割する例

#include <iostream>
#include <string>
#include <boost/algorithm/string.hpp>
#include <boost/foreach.hpp>

std::string s = "2011/02/09 20:19:33";
std::list<std::string> results;
//スラッシュ、スペース、コロンで分割
boost::split(results, s, boost::is_any_of("/ :"));

BOOST_FOREACH(std::string p, results) {
  std::cout << p << std::endl;
}

空白文字で分割

#include <iostream>
#include <string>
#include <boost/algorithm/string.hpp>
#include <boost/foreach.hpp>

std::string s = "More Effective C++";
std::list<std::string> results;
//空白文字で分割
boost::split(results, s, boost::is_space());

BOOST_FOREACH(std::string p, results) {
  std::cout << p << std::endl;
}