読者です 読者をやめる 読者になる 読者になる

ストリーム入出力を使用して、文字コードがUTF-8なファイルを読み書きする

C++Builder Tips C++ Tips

Boostのutf8_codecvt_facetをインクルードして、imbueでストリームに設定してやればOK。
libs/detail/utf8_codecvt_facet.cppもインクルードしてやらないとリンクエラーが発生。
UnicodeStringをstd::wstringにしてもちゃんと読み書きできる。

参考URL:
http://grayhole.blogspot.com/2008/11/utf8.html
http://d.hatena.ne.jp/Cryolite/20041029

#include <iostream>
#include <fstream>
#include <vcl.h>
#pragma hdrstop

#define BOOST_UTF8_BEGIN_NAMESPACE \
namespace boost { namespace detail {
#define BOOST_UTF8_DECL
#define BOOST_UTF8_END_NAMESPACE }}
#include <boost/detail/utf8_codecvt_facet.hpp>
#include <libs/detail/utf8_codecvt_facet.cpp>
#undef BOOST_UTF8_END_NAMESPACE
#undef BOOST_UTF8_DECL
#undef BOOST_UTF8_BEGIN_NAMESPACE

#include <tchar.h>
//---------------------------------------------------------------------------


#pragma argsused
int _tmain(int argc, _TCHAR* argv[])
{
  UnicodeString s0(L"12345");
  UnicodeString s1(L"あいうえお");
  UnicodeString s2(L"かきくけこ");
  UnicodeString s3(L"abcdef");

  std::locale::global(std::locale(""));

  // 出力
  std::wofstream ofs;
  ofs.imbue(std::locale(ofs.getloc(), new boost::detail::utf8_codecvt_facet));
  ofs.open("TEST.TXT");
  ofs << s0 << s1 << s2 << s3 << std::endl;
  ofs.close();

  // 入力
  UnicodeString ss;
  std::wifstream ifs;
  ifs.imbue(std::locale(ifs.getloc(), new boost::detail::utf8_codecvt_facet));
  ifs.open("TEST.TXT");
  ifs >> ss;
  ifs.close();

  ShowMessage(ss);

  return 0;
}

キモはファセットと呼ばれるオブジェクトで、こいつが文字コードの変換や文字種の判定、比較といった文字コードがからんだ厄介な処理を請け負ってくれる*1C++0xではUTF-8UTF-16を処理するファセットが用意される。*2あと、newしてもロカール側でdeleteしてくれるのでファセットオブジェクトのdeleteは不要。*3

*1:詳細はC++標準ライブラリチュートリアル&リファレンス (ASCII Addison Wesley Programming Series)にのっているけど、これ、プレミア付きの絶版本じゃん!

*2:http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2010/n3092.pdfのP708

*3:ファセットのデストラクタにはアクセスできないから丸投げでいいみたい