C++Builder 2009のTMemIniFileとエンコードの挙動を調べた。
結論から先に言うと、エンコードを指定する場合は「TEncoding::Unicode」を使うこと。
TEncoding::UTF8やEncoding:UTF7を使うと、不可思議な挙動に悩まされる。
エンコードを指定しないC++Builder 2007と同じ書き方。
//書き込み
std::unique_ptr<TMemIniFile> ini(new TMemIniFile(path));
ini->WriteString(L"日本語", L"こんにちは", L"こんにちは");
ini->WriteString(L"中国語", L"こんにちは", L"你好");
ini->UpdateFile();
ファイルには、ANSIのデフォルトのコードページ(Shift_JIS)で保存される。
したがって、文字化けする。
//読み込み
std::unique_ptr<TMemIniFile> ini(new TMemIniFile(path));
ini->ReadString(L"日本語", L"こんにちは", "no data"); //=> こんにちは
ini->ReadString(L"中国語", L"こんにちは", "no data"); //=> ?好
エンコードにTEncoding.Unicodeを指定する書き方。
リトルエンディアンバイトオーダーのUTF-16で保存される。
ファイルには16進数 FFFE のバイトオーダーマークが付く。
//書き込み
std::unique_ptr<TMemIniFile> ini(new TMemIniFile(path, TEncoding::Unicode));
ini->WriteString(L"日本語", L"こんにちは", L"こんにちは");
ini->WriteString(L"中国語", L"こんにちは", L"你好");
ini->UpdateFile();
//読み込み
std::unique_ptr<TMemIniFile> ini(new TMemIniFile(path, TEncoding::Unicode));
ini->ReadString(L"日本語", L"こんにちは", "no data"); //=> こんにちは
ini->ReadString(L"中国語", L"こんにちは", "no data"); //=> 你好
書き込み、読み込みともに問題なく動作する。
なお、ファイルにバイトオーダーマークが付いているので、エンコードを指定しなくても、自動的に識別してくれる。
std::unique_ptr<TMemIniFile> ini(new TMemIniFile(path));
ini->ReadString(L"日本語", L"こんにちは", "no data"); //=> こんにちは
ini->ReadString(L"中国語", L"こんにちは", "no data"); //=> 你好
エンコードにTEncoding::UTF8を指定する書き方。
UTF-8形式で保存される。
ファイルには、16進数 EFBBBF のバイトオーダーマークが付く。
//書き込み
std::unique_ptr<TMemIniFile> ini(new TMemIniFile(path, TEncoding::UTF8));
ini->WriteString(L"日本語", L"こんにちは", L"こんにちは");
ini->WriteString(L"中国語", L"こんにちは", L"你好");
ini->UpdateFile();
//読み込み
std::unique_ptr<TMemIniFile> ini(new TMemIniFile(path, TEncoding::UTF8));
Memo1->Lines->Add(ini->ReadString(L"日本語", L"こんにちは", "no data")); //=> こんにちは
Memo1->Lines->Add(ini->ReadString(L"中国語", L"こんにちは", "no data")); //=> 你好 / ?好
ここで、奇妙な動作になる。
ファイルが存在しないとき、つまり新規保存になるときは正しく、UTF-8で保存される。
ところが、すでにファイルが存在するときには、ANSIのデフォルトのコードページ(Shift_JIS)で保存されてしまう。
TEncoding::UTF8ではなくTEncoding::UTF7を使っても、同様の現象が起こる。