C++ 文本文件不会保存在 Unicode 中,它一直保存在 ANSI 中

C++ Text file won't save in Unicode, it keeps saving in ANSI

所以基本上,我需要能够以 Unicode 创建文本文件,但无论我做什么,它都会以 ANSI 保存。

这是我的代码:

    wchar_t name[] = L"‎中國哲學書電子化計劃";
    FILE * pFile;
    pFile = fopen("chineseLetters.txt", "w");

    fwrite(name, sizeof(wchar_t), sizeof(name), pFile);
    fclose(pFile);

这是我的 "chineseLetters.txt":

的输出
     -NWòTx[øfû–P[SŠƒR  õ2123

此外,该应用程序是 MBCS,不能更改为 Unicode,因为它需要同时使用 Unicode 和 ANSI。

非常感谢您的帮助。谢谢

感谢大家的快速回复!有效!

简单地加上 L"\uFFFE 中国哲学书电子化计划" 仍然没有用,文本编辑器仍然将它识别为 CP1252 所以我做了 2 个 fwrite 而不是一个,一个用于 BOM,一个用于字符,现在是我的代码:

    wchar_t name[] = L"‎中國哲學書電子化計劃";
    unsigned char bom[] = { 0xFF, 0xFE };
    FILE * pFile;
    pFile = fopen("chineseLetters.txt", "w");
    fwrite(bom, sizeof(unsigned char), sizeof(bom), pFile);
    fwrite(name, sizeof(wchar_t), wcslen(name), pFile);
    fclose(pFile);

"Unicode" 是一个通用术语,您可能需要澄清 哪种 Unicode 您打算在文件中使用的编码

Unicode UTF-8 是一个常见的选择(它特别适合跨不同平台交换文本数据,因为它没有 "endiannes" 的概念,与 UTF-16 不同,没有 little-endian/big-endian 混淆,它在 Internet 上广泛使用),但也有其他选项(例如 Windows 上的 UTF-16,它直接映射到 wchar_t-Visual C++ 中的字符串)。

如果您使用的是 Visual C++,您可以在 fopen()(或 _wfopen())的第二个参数中指定一个 ccs 属性,选择你想要的编码,例如"ccs=UTF-8" 为 UTF-8 编码。
您可以在 the MSDN documentation of fopen() 上阅读更多详细信息,例如:

fopen supports Unicode file streams. To open a Unicode file, pass a ccs flag that specifies the desired encoding to fopen, as follows.

fp = fopen("newfile.txt", "rt+, ccs= encoding ");

Allowed values of encoding are UNICODE, UTF-8, and UTF-16LE.

我认为 UNICODE 他们的意思是 UTF-16BE (即 big-endian UTF-16);其他两个选项很明确。


编辑

我试过这段代码,在使用 Unicode UTF-8 保存中文文本时效果很好(我用的是 Visual Studio 2013):

wchar_t name[] = L"‎中國哲學書電子化計劃";
FILE * file = fopen("C:\TEMP\ChineseLetters.txt", "wt, ccs=UTF-8");
...check for error...

fwrite(name, sizeof(wchar_t), _countof(name)-1, file);
fclose(file);

请注意,在将中文文本粘贴到源文件中并保存后,Visual Studio 编辑器发现需要将源文件保存为 Unicode 以不丢失文本信息,并显示 dialog-box 要求确认。
因此,考虑将源文件保存为 Unicode,如果其中有一些 "hard-coded" Unicode 文本(在 production-quality Windows/C++ 代码中,您可能想要将文本保存在 资源 文件中)。

另请注意,我在 fwrite() 调用中使用 _countof() 而不是 sizeof()
你有:

fwrite(name, sizeof(wchar_t), sizeof(name), file);

但那是 错误的 ,因为您要将 wchar_ts 的计数指定为第三个参数,而不是以字节为单位的总大小(请注意,在 MSVC 中,sizeof(wchar_t) == 2,即 wchar_t 是两个 char,即 两个字节 )。

此外,你必须考虑 -1wchar_ts 中的总缓冲区长度,因为你不想写 NUL-在 Unicode 字符串缓冲区中终止 wchar_t
(对于未知静态大小的 Unicode UTF-16 wchar_t 字符串,您可以简单地使用 wcslen() 来获取不包括终止 NULwchar_t 的计数)。

上面写的UTF-8文件在Word中正确打开的方式是这样的:

I need to be able to create a text file in Unicode

Unicode不是编码,你是说UTF-16LE吗?这是双字节代码单元编码 Windows x86/x64 用于内存中的内部字符串存储,一些 Windows 应用程序如记事本误导性地将 UTF-16LE 描述为“Unicode” UI.

fwrite(name, sizeof(wchar_t), sizeof(name), pFile);

您已将字符串的内存存储直接复制到文件中。如果你在 Windows/MSVCRT 下编译它,那么因为内部存储编码是 UTF-16LE,所以你生成的文件被编码为 UTF-16LE。如果你在其他环境中编译它,你会得到不同的结果。

And here is the output of my "chineseLetters.txt": -NWòTx[øfû–P[SŠƒR õ2123

如果您将文件误解为 Windows 代码页 1252(西欧),UTF-16LE 编码数据就是这个样子。

如果您已将文件加载到 Windows 应用程序(如记事本)中,它可能不知道该文件包含 UTF-16LE 编码数据,因此默认使用您的默认值读取文件locale-specific (ANSI, mbcs) 代码页作为编码,导致上面的 mojibake.

当你制作一个UTF-16文件时,你应该在它的开头放置一个字节顺序标记字符U+FEFF,让消费者知道它是UTF-16LE还是UTF-16BE。这也给像记事本这样的应用程序提示文件包含 UTF-16,而不是 ANSI。所以您可能会发现写入 L"\uFEFF‎中國哲學書電子化計劃" 会使输出文件在记事本中显示得更好。

但最好将 wchar_ts 转换为 char 字节,采用明确规定的特定所需编码(例如 UTF-8),而不是依赖于内存中的存储格式C库正好用到。在 Win32 上,您可以使用 WideCharToMultibyte API 或 Mr.C64 所述的全开 ccs 来执行此操作。如果您选择使用 ccs 编写 UTF-16LE 文件,它将为您放入 BOM。