0

ANSI ファイルを読み書きする MFC プロジェクトがあります。アプリケーションの文字セットはUnicodeに設定されています。

補遺
私のコンテキストでは、レガシーソフトウェア間のコンバーターについて話しているため、入力ファイルと出力ファイルのエンコーディングを変更/影響する可能性はありません。予想される文字エンコーディングは、実際にはwindows-1252です。

いくつかのファイルを読み書きしているときに、 で読み書きすると、のようなめったに使用されない文字がŠ (0x8A)に置き換えられることに気付きました。との間の範囲でどの文字が影響を受けるかを確認するためのテストファイルを作成しました。? (0x3F)CStdioFile0x300xFF

これらの文字をテストファイル(ANSI コード)にコピーしました(0x30 から 0xFF までの文字)

Beyond Compare によって解釈される入力ファイル構造

結果のファイルは次のようになります

Beyond Compare によって解釈される出力ファイル構造

変更された文字はすべて同じ地域にあり、すべて0x3F '?'- から0x80まで変更されてい0x9Fます。奇妙なことに、影響を受けなかった0x810x8D0x90などの例外がいくつかあります。0x9D

動作をテストするコード例:

//prepare vars
CFileException fileException;
CStdioFile filei;
CStdioFile fileo;
CString strText;


//open input file
filei.Open(TEXT("test.txt"), CFile::modeRead | CFile::shareExclusive | CFile::typeText, &fileException);

//open output file 
fileo.Open(TEXT("testout.txt"), CFile::modeCreate | CFile::modeWrite | CFile::shareExclusive | CFile::typeText, &fileException);

//read and write 
BOOL eof = filei.ReadString(strText) <= 0;
fileo.Write(CStringA(strText), CStringA(strText).GetLength());

//clean up
filei.Close();
fileo.Close();

なぜそれを行うのですか?すべての文字を保持するにはどうすればよいですか?

Unicode モードを無効にすると問題は解決しますが、残念ながら私の場合はオプションではありません。


要約
以下は、受け入れられた回答から私にとって役に立ったものを抜粋したものです。

コンストラクターを呼び出すだけでからCStringWに変換しないでください。CStringAUnicode から "ANSI" (Windows1252) に変換する場合は、次を使用しますCW2A

CStringA strTextA(strText, CP_ACP)` //CP_ACP converts to ANSI
fileo.Write(strTextA, strTextA.GetLength());    

さらに簡単: のCStdioFile::WriteString代わりにメソッドを使用しますCStdioFile::WriteS

fileo.Open(TEXT("testout.txt"), CFile::modeCreate | CFile::modeWrite | CFile::shareExclusive | CFile::typeText, &fileException);
fileo.WriteString(strText);
4

1 に答える 1

1

問題は、デフォルトでこのCStdioFile::Open方法を使用すると、 CStdioFileANSI ファイルの読み取り/書き込みのみが可能ですが、ファイル ストリームを自分で開くことができ、正しいエンコーディングを指定できるようになることです。

FILE* fStream = NULL;
errno_t e = _tfopen_s(&fStream, _T("C:\\Files\\test.txt"), _T("rt,ccs=UNICODE"));
if (e != 0) 
    return; // failed to open file 
CStdioFile f(fStream);  
CString sRead;
f.ReadString(sRead);
f.Close();

ファイルを書きたい場合は、_T("wt,ccs=UNICODE")一連のオプションを使用する必要があります。

もう 1 つの明らかな問題は、Writeの代わりに を呼び出すことですWriteString。の場合は変換する必要はありませCStringWん。何らかの理由で使用する必要がある場合は、 with を呼び出して適切に変換する必要があります。CStringAWriteStringWriteCStringWCStringACW2A()CP_UTF8

andの代わりに汎用CFileクラス andを使用するサンプル コードを次に示します。WriteCStdioFileWriteString

CStringW sText = L"Привет мир";

CFile file(_T("C:\\Files\\test.txt"), CFile::modeWrite | CFile::modeCreate);

CStringA sUTF8 = CW2A(sText, CP_UTF8);
file.Write(sUTF8 , sUTF8.GetLength());

CFileファイルとメソッドを開くコンストラクターは、例外の種類をWriteスローすることに注意してください。CFileExceptionしたがって、それらを処理する必要があります。

テキスト ファイル ストリームを開くときは、次のオプションを使用してエンコードの種類を指定します。

  • "ccs=UNICODE"UTF-16(ビッグエンディアン)に対応
  • "ccs=UTF-8"UTF-8に対応
  • "ccs=UTF-16LE"UTF-16LE(リトルエンディアン)に対応
于 2015-11-27T18:21:39.727 に答える