CStdioFile 写宽字节(Unicode 字符)时写不进去,而写窄字节(ANSI 字符)正常,原因通常是 CStdioFile 默认是以文本方式按当前本地代码页写入的,它不支持宽字符直接写入。

🔧 原因分析

CStdioFile::WriteString 有两个重载版本:

void WriteString(LPCTSTR lpsz);
void WriteString(LPCWSTR lpsz); // 仅在 UNICODE 编译下存在

但问题在于:

  1. CStdioFile 不是宽字符流类,内部使用的是 CFile, FILE*, 或 HANDLE,而非 wchar_t 字符流;

  2. 当你传入 wchar_t* 的字符串(比如用 CStringW),它实际上会直接把 Unicode 内存写进去,而不做编码转换;

  3. 如果你打开文件时用的是 ASCII 模式(CFile::modeCreate | CFile::modeWrite),就会导致写入乱码或写不进去;

  4. 有些平台下,写宽字节时会因为遇到 \0 而提前终止写入(尤其是如果宽字节中包含 null 字节对时)。


✅ 正确做法

✅ 方法一:用 CFile + 转码(推荐)

你应该手动将宽字节转为 UTF-8 或 ANSI,再写进去:

CStringW wideStr = L"你好,世界!";

// 转为 UTF-8
int len = WideCharToMultiByte(CP_UTF8, 0, wideStr, -1, NULL, 0, NULL, NULL);
char* utf8Str = new char[len];
WideCharToMultiByte(CP_UTF8, 0, wideStr, -1, utf8Str, len, NULL, NULL);

// 用 CFile 写入
CFile file;
file.Open(_T("output.txt"), CFile::modeCreate | CFile::modeWrite);
file.Write(utf8Str, len - 1); // 不写 null 结尾
file.Close();

delete[] utf8Str;

✅ 方法二:用 CStdioFile 写入 UTF-8(需手动 BOM)

如果你坚持使用 CStdioFile,可以手动写入 UTF-8 BOM,然后写转码后的字符串:

CStringW wideStr = L"你好,世界!";

// 写 UTF-8 BOM
BYTE bom[] = { 0xEF, 0xBB, 0xBF };

CStdioFile file(_T("utf8_output.txt"), 
    CFile::modeCreate | CFile::modeWrite | CFile::typeBinary);
file.Write(bom, sizeof(bom));

// 转为 UTF-8 再写
int len = WideCharToMultiByte(CP_UTF8, 0, wideStr, -1, NULL, 0, NULL, NULL);
char* utf8Str = new char[len];
WideCharToMultiByte(CP_UTF8, 0, wideStr, -1, utf8Str, len, NULL, NULL);
file.Write(utf8Str, len - 1);
file.Close();

delete[] utf8Str;

❌ 错误方式示例(容易出错)

CStringW str = L"你好";
CStdioFile file(_T("test.txt"), CFile::modeCreate | CFile::modeWrite);
file.WriteString(str); // ❌ 有可能写不进去或乱码

总结

  • CStdioFile 默认处理的是 ANSI 编码;

  • 如果你要写宽字节,请先转为 UTF-8 或本地代码页

  • 更通用推荐使用 CFile 并明确指定编码格式。