0

我有一个 MFC 项目,它从 ANSI 文件读取和写入。应用程序的字符集设置为Unicode

附录
我无法更改/影响输入和输出文件的编码,因为在我的上下文中,我们谈论的是旧软件之间的转换器。预期的字符编码实际上是windows-1252

在读写一些文件时,我注意到一些很少使用的字符,比如在Š (0x8A)用. 我创建了一个测试文件来查看在和之间的范围内哪些字符受到影响。? (0x3F)CStdioFile0x300xFF

我将这些字符复制到一个测试文件(ANSI 编码)(从 0x30 到 0xFF 的字符)

Beyond Compare 解释的输入文件结构

结果文件如下所示

Beyond Compare 解释的输出文件结构

更改的字符都在同一区域周围,并且都更改为0x3F '?'- 从0x80up to开始0x9F。奇怪的是,有一些例外,如0x81, 0x8D0x90并且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来转换。CStringA从 Unicode 转换为 "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方法,CStdioFile则只能读取/写入 ANSI 文件,但您可以自己打开文件流,然后您将能够指定正确的编码:

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")一组选项。

另一个明显的问题是您调用Write而不是WriteString. 无需转换CStringWCStringA. WriteString如果由于某种原因需要使用Write,您必须通过调用 to正确转换CStringW为with 。CStringACW2A()CP_UTF8

这是使用通用CFile类的示例代码 andWrite代替CStdioFileand WriteString

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 回答