CStdioFile
写宽字节(Unicode 字符)时写不进去,而写窄字节(ANSI 字符)正常,原因通常是 CStdioFile
默认是以文本方式按当前本地代码页写入的,它不支持宽字符直接写入。
🔧 原因分析
CStdioFile::WriteString
有两个重载版本:
void WriteString(LPCTSTR lpsz);
void WriteString(LPCWSTR lpsz); // 仅在 UNICODE 编译下存在
但问题在于:
CStdioFile
不是宽字符流类,内部使用的是CFile
,FILE*
, 或HANDLE
,而非wchar_t
字符流;当你传入
wchar_t*
的字符串(比如用CStringW
),它实际上会直接把 Unicode 内存写进去,而不做编码转换;如果你打开文件时用的是 ASCII 模式(
CFile::modeCreate | CFile::modeWrite
),就会导致写入乱码或写不进去;有些平台下,写宽字节时会因为遇到
\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
并明确指定编码格式。