UNICODEテキストファイルにBOMを付ける方法

[戻る]
花の慶次 2013/05/27(月) 16:41:11
VS2010 MFC ダイアログベースアプリです。
コンマ区切りCSVファイルを出力するプログラムを作っています。
UNICODE文字を扱えるようにしたいので、プロジェクトは「UNICODE 文字セットを使用す
る」としています。
サンプルとして、次のコードを書きました。

void CCSVDlg::OnBnClickedButton1()
{
    CString sData[] = {_T("いつやるか。"), _T("今でしょ!"), _T("あとで"), _T
("やります。")};
    CString sSave;
    sSave = sData[0] + _T(",") + sData[1] + _T("\n");
    sSave += sData[2] + _T(",") + sData[3] + _T("\n");
    CFile f;
    f.Open(_T("test1.csv"), CFile::modeCreate | CFile::modeWrite);
    f.Write(sSave, sSave.GetLength() * sizeof(TCHAR));
    f.Close();
}

これで test1.csv というファイルが出来ます。
MIFESというテキストエディタで調べると、UTF-16のファイルとなっているようです。
しかし、このファイルをエクセルで開くと文字化けします。
エクセルで編集できるUNICODEファイルを出力したいのです。

調べたら、エクセルで開けるUNICODEのCSVファイルは、
@コンマ区切りではなく、タブ区切りであること。
AUTF-16 LE の BOM付きであること。
と解りました。

@は、前記の _T(",") を _T("\t") に置き換えました。
Aは、ファイルの先頭に、0xFF 0xFE の2バイトを付ければいいらしいのですが、どの
ようにプログラムコードを書けばいいかが解りません。

どうぞご教授ください。よろしくお願いいたします。

επιστημη [E-Mail] [HomePage] 2013/05/28(火) 05:33:03
> @コンマ区切りではなく、タブ区切りであること。



この時点でCSVじゃなくなりますけど、かまわんのですか?



> Aは、ファイルの先頭に、0xFF 0xFE の2バイトを付ければいいらしいのですが



    CString sSave = L"\xFFFE";

    sSave += sData[0] + _T(",") + sData[1] + _T("\n");



これじゃダメ?

花の慶次 2013/05/28(火) 08:00:40
επιστημη様、有り難うございます。

> この時点でCSVじゃなくなりますけど、かまわんのですか?
はい、かまいません。

CString sSave = L"\xFFFE";
sSave += sData[0] + _T("\t") + sData[1] + _T("\n");

これでやってみましたが、文字化けします。

仲澤@失業者 2013/05/28(火) 09:14:26
エクセルのバージョンにもよるとは思いますが、

CSVとして完全に自動的に認識できるUnicodeは



 1.UTF-16LE タブ区切り



のようですね。ただし、

エクセルを開いてから読み込む場合で、ウィザードDLGが出ても良いのなら、



 2.UTF-8(BOM付き) (区切りはウィザードで設定する)



もOKのようですよ。

特にUnicodeにこだわらなければShift-JISが最も安全ですけどね。

akey 2013/05/28(火) 09:19:29
エンディアン的に逆ですかね
>CString sSave = L"\xFFFE";
CString sSave = L"\xFEFF";

蒼の洞窟 2013/05/28(火) 09:25:42
文字列に無理やりしないでバイトとして書き出したほうが簡明かも。

>    f.Open(_T("test1.csv"), CFile::modeCreate | CFile::modeWrite);
BYTE bom = {0xff, 0xfe};
f.Write(bom, sizeof(bom));
>    f.Write(sSave, sSave.GetLength() * sizeof(TCHAR));
>    f.Close();

akey 2013/05/28(火) 09:39:25
構文的に配列ですかね
>BYTE bom = {0xff, 0xfe};
BYTE bom[] = {0xff, 0xfe};

蒼の洞窟 2013/05/28(火) 10:36:46
>akeyさん
普通に間違えてましたorz

ご指摘感謝します。

花の慶次 2013/05/28(火) 16:10:36
[[解決]]
出来ました。

    CString sData[] = {_T("いつやるか。"), _T("今でしょ!"), _T("あとで"), _T
("やります。")};
    CString sSave;
    sSave = sData[0] + _T("\t") + sData[1] + _T("\n");
    sSave += sData[2] + _T("\t") + sData[3] + _T("\n");
    BYTE bom[] = {0xff, 0xfe};
    CFile f;
    f.Open(_T("test1.csv"), CFile::modeCreate | CFile::modeWrite);
    f.Write(bom, sizeof(bom));
    f.Write(sSave, sSave.GetLength() * sizeof(TCHAR));
    f.Close();

これで、タブ区切りのCSV?ファイルが出来て、ダブルクリックでエクセルが開き、文字
化けなく正常に表示されました。

本当はコンマ区切りにしたいので、コンマ区切りで作成した場合もやってみました。
@ 作成したファイルをダブルクリックすると、エクセルが開いて、文字化けはありませ
んが、コンマも文字として認識した文字列「いつやるか。,今でしょ!」が表示されま
す。
A エクセルを起動してからファイルを開き、ウィザードDLGで”カンマ区切り”を選択
して進むと、正常に表示されました。
B 次に、エクセル上で編集を行い、上書き保存のアイコンで保存すると、タブ区切りの
ファイルに変化しました。
C 名前を付けて保存で「CSV(カンマ区切り)」で保存すると、正常に保存されまし
た。
D そのファイルは次回ダブルクリックでも正常に開きました。

Aの方法で開きCの方法で保存・・・これを励行すればコンマ区切りでも使えそうで
す。

それにしても、エクセルの Unicode 対応は中途半端と思います。

Dの理由が解りません。BOM以外の何かをエクセルが書き込んだのでしょうか?

蒼の洞窟様はじめ、皆様ありがとうございました。

瀬戸っぷ [E-Mail] 2013/05/28(火) 17:07:46
>Dの理由が解りません。BOM以外の何かをエクセルが書き込んだのでしょうか?

Cで書き出したファイルがShift-JISだった…とかではないですか?

花の慶次 2013/05/28(火) 18:56:20
これは、これは、親分! 大笑い (^o^)

Cで書き出したファイルは "Shift-JIS" でした。
やはりタブ区切りでないとエクセルではまともに扱えませんね。

タブ区切りだと、何かと扱いにくい。
Unicode が大前提なので、エクセルに阿て(おもねて)タブ区切りにするか、エクセル
を無視してコンマ区切りで押し通すか・・・うーむ

ありがとうございました。

古いスレッドには追加発言できません。