web-dev-qa-db-ja.com

UTF-8、CString、CFile? (C ++、MFC)

私は現在、特にUTF-8で動作する必要があるMFCプログラムに取り組んでいます。ある時点で、UTF-8データをファイルに書き込む必要があります。そのために、私はCFilesとCStringsを使用しています。

Utf-8(より正確にはロシア語の文字)データをファイルに書き込むと、出力は次のようになります。

Ðàñïå÷àòàíî:
Ñèñòåìà
Ïðîèçâîäñòâî

など。これは確かにutf-8ではありません。このデータを正しく読み取るには、システム設定を変更する必要があります。非ASCII文字をロシア語のエンコーディングテーブルに変更することはできますが、ラテン語ベースの非ASCII文字はすべて失敗します。とにかく、それが私のやり方です。

CFile CSVFile( m_sCible, CFile::modeCreate|CFile::modeWrite);
CString sWorkingLine;
//Add stuff into sWorkingline
CSVFile.Write(sWorkingLine,sWorkingLine.GetLength());
//Clean sWorkingline and start over

私は何かが足りないのですか?代わりに他のものを使用しますか?見逃したキャッチはありますか?私はあなたの知恵と経験、仲間のプログラマーに注目します。

編集:もちろん、私がちょうど質問をしたとき、私はついに面白いかもしれない何かを見つけました、それは見つけることができます ここ 。私はそれを共有するかもしれないと思った。

編集2:

さて、ファイルにBOMを追加しました。ファイルには中国語の文字が含まれています。おそらく、行をUTF-8に変換しなかったためです。私がやったボムを追加するには...

char BOM[3]={0xEF, 0xBB, 0xBF};
CSVFile.Write(BOM,3);

そしてその後、私は追加しました...

    TCHAR TestLine;
    //Convert the line to UTF-8 multibyte.
    WideCharToMultiByte (CP_UTF8,0,sWorkingLine,sWorkingLine.GetLength(),TestLine,strlen(TestLine)+1,NULL,NULL);
    //Add the line to file.
    CSVFile.Write(TestLine,strlen(TestLine)+1);

しかし、TestLineの長さを取得する方法が本当にわからないため、コンパイルできません。 strlenはTCHARを受け入れないようです。修正され、代わりに1000の静的長さを使用しました。

編集3:

だから、私はこのコードを追加しました...

    wchar_t NewLine[1000];
    wcscpy( NewLine, CT2CW( (LPCTSTR) sWorkingLine ));
    TCHAR* TCHARBuf = new TCHAR[1000];

    //Convert the line to UTF-8 multibyte.
    WideCharToMultiByte (CP_UTF8,0,NewLine,1000,TCHARBuf,1000,NULL,NULL);

    //Find how many characters we have to add
    size_t size = 0;
    HRESULT hr = StringCchLength(TCHARBuf, MAX_PATH, &size);

    //Add the line to the file
    CSVFile.Write(TCHARBuf,size);

正常にコンパイルされますが、新しいファイルを見ると、この新しいコードがすべてなかったときとまったく同じです(例:Ðàñïå÷àòàíî:)。一歩前進しなかったような気がしますが、勝利との隔たりは小さなことだと思います。

編集4:

ネイトが尋ねたように、以前に追加したコードを削除し、代わりに彼のコードを使用することにしました。つまり、行を追加すると、次のようになります...

        CT2CA outputString(sWorkingLine, CP_UTF8);

    //Add line to file.
    CSVFile.Write(outputString,::strlen(outputString));

すべてが正常にコンパイルされますが、ロシア語の文字は???????として表示されます。近づいていますが、それでもそうではありません。ところで、私を助けようとした/試みたすべての人に感謝したいと思います、それは非常に感謝しています。私はしばらくこれに固執してきました、私はこの問題がなくなるのを待つことができません。

最終編集(私は願っています)テキストを出力する新しい方法で間違っていたUTF-8文字を最初に取得する方法(私は本当に知らずに再エンコードしました)を変更することによって、許容できる結果が得られました。ファイルの先頭にUTF-8BOM文字を追加することで、Excelなどの他のプログラムでUnicodeとして読み取ることができます。

やあ!みんなありがとう!

16
SeargX

データを出力するときは、実行する必要があります(これは、Unicodeモードでコンパイルしていることを前提としています。これを強くお勧めします)。

CString russianText = L"Привет мир";

CFile yourFile(_T("yourfile.txt"), CFile::modeWrite | CFile::modeCreate);

CT2CA outputString(russianText, CP_UTF8);
yourFile.Write(outputString, ::strlen(outputString));

_UNICODEが定義されていない場合(代わりにマルチバイトモードで作業している場合)、入力テキストがどのコードページにあるかを知り、それを使用できるものに変換する必要があります。この例は、UTF-16形式のロシア語テキストを操作してUTF-8に保存する方法を示しています。

// Example 1: convert from Russian text in UTF-16 (note the "L"
// in front of the string), into UTF-8.
CW2A russianTextAsUtf8(L"Привет мир", CP_UTF8);
yourFile.Write(russianTextAsUtf8, ::strlen(russianTextAsUtf8));

ロシア語のテキストは、KOI-8Rなどの他のコードページにある可能性があります。その場合、他のコードページからUTF-16に変換する必要があります。次に、UTF-16をUTF-8に変換します。変換マクロを使用してKOI-8RからUTF-8に直接変換することはできません。これは、KOI-8Rが常に狭いテキストをシステムコードページに変換しようとするためです。したがって、簡単な方法はこれを行うことです。

// Example 2: convert from Russian text in KOI-8R (code page 20866)
// to UTF-16, and then to UTF-8. Conversions between UTFs are
// lossless.
CA2W russianTextAsUtf16("\xf0\xd2\xc9\xd7\xc5\xd4 \xcd\xc9\xd2", 20866);
CW2A russianTextAsUtf8(russianTextAsUtf16, CP_UTF8);
yourFile.Write(russianTextAsUtf8, ::strlen(russianTextAsUtf8));

BOMは必要ありません(オプションです。特別な理由がない限り、BOMは使用しません)。

必ずこれを読んでくださいhttp://msdn.Microsoft.com/en-us/library/87zae4a3(VS.80) .aspxCT2CAを誤って使用すると(たとえば、代入演算子を使用して)、問題が発生します。リンクされたドキュメントページには、使用方法と使用しない方法の例が示されています。

さらに詳しい情報:

  • CT2CA[〜#〜] c [〜#〜]constを示します。可能な場合は使用しますが、一部の変換は非constバージョンのみをサポートします(例:CW2A)。
  • CT2CA[〜#〜] t [〜#〜]は、 fromLPCTSTRに変換しています。したがって、コードが_UNICODEフラグを使用してコンパイルされているかどうかに関係なく機能します。 CW2A(where[〜#〜] w [〜#〜]はワイド文字を示します)。
  • CT2CA[〜#〜] a [〜#〜]は、 「ANSI」(8ビット文字)文字列に変換しています。
  • 最後に、CT2CAの2番目のパラメーターは、変換先のコードページを示します。

逆変換(UTF-8からLPCTSTRへ)を行うには、次のようにします。

CString myString(CA2CT(russianText, CP_UTF8));

この場合、fromからUTF-8形式の「ANSI」文字列をLPCTSTRに変換しています。 LPCTSTRは、常にUTF-16(_UNICODEが定義されている場合)または現在のシステムコードページ(_UNICODEが定義されていない場合)であると見なされます。

26
Nate

sWorkingLineをUTF-8に変換してから、ファイルに書き込む必要があります。

WideCharToMultiByteCP_UTF8コードページを選択すると、Unicode文字列をUTF-8に変換できます。 MultiByteToWideChar ASCII文字をユニコードに変換できます。

6

Unicodeを使用していることを確認してください(TCHARはwchar_tです)。次に、データを書き込む前に、WideCharToMultiByte Win32API関数を使用してデータを変換します。

0
user261840