C语言调用ReadFile读取文件存入wchar_t输出方块问号乱码如何解决
ReadFile读取文本到wchar_t数组输出乱码的错误原因
你的代码存在4个核心逻辑错误,直接导致输出乱码:
- 编码匹配错误:
ReadFile仅做原始字节读取,不会自动完成编码转换。Windows平台wchar_t对应2字节长度的UTF-16 LE编码,只有当a.txt本身存储为UTF-16 LE格式时,直接读取字节到wchar_t数组才可能正确解析。但系统默认生成的txt文件多为GBK(ANSI)或UTF-8编码,属于单/变长多字节编码,强行按2字节一组解析为宽字符必然出现乱码。 - 内存分配逻辑错误:你获取的
sizeF是文件的字节总长度,分配内存时写malloc(sizeF * sizeof(wchar_t))会申请2倍于实际需求的内存,属于无意义的资源浪费。 - 字符串终止位置错误:
wchar_t数组的索引以宽字符为单位计数,而非字节。你直接在readBuffer[sizeF]位置写入终止空字符,位置完全错误——若文件为UTF-16编码,实际宽字符数为字节数/2,该写入位置要么越界,要么导致字符串截断异常。 - 缺少必要的错误处理与BOM兼容:代码没有判断
CreateFileW的返回值是否为INVALID_HANDLE_VALUE,也没有使用ReadFile输出的bytesRead参数确认实际读取字节数;即便文件为UTF-16编码,Windows默认保存的Unicode文本会在开头带2字节BOM头(0xFFFE),直接输出会出现异常字符。
修正方案
根据目标文件的实际编码选择对应处理逻辑:
场景1:a.txt为UTF-8/ANSI编码(绝大多数默认场景)
先按原始字节读取文件内容,再通过MultiByteToWideChar完成编码转换为UTF-16格式的宽字符串,核心实现参考:
#include <stdio.h> #include <windows.h> #include <io.h> #include <fcntl.h> #include <stdlib.h> int main() { _setmode(_fileno(stdout), _O_U16TEXT); HANDLE fh = CreateFileW( L"a.txt", GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (fh == INVALID_HANDLE_VALUE) { return 1; } LARGE_INTEGER size; GetFileSizeEx(fh, &size); DWORD byteSize = size.QuadPart; char* byteBuf = (char*)malloc(byteSize + 1); DWORD bytesRead = 0; if (!ReadFile(fh, byteBuf, byteSize, &bytesRead, NULL)) { CloseHandle(fh); free(byteBuf); return 1; } byteBuf[bytesRead] = '\0'; CloseHandle(fh); // 若文件为ANSI编码,将CP_UTF8替换为CP_ACP int wLen = MultiByteToWideChar(CP_UTF8, 0, byteBuf, -1, NULL, 0); wchar_t* readBuffer = (wchar_t*)malloc(wLen * sizeof(wchar_t)); MultiByteToWideChar(CP_UTF8, 0, byteBuf, -1, readBuffer, wLen); wprintf(L"%s\n", readBuffer); free(byteBuf); free(readBuffer); return 0; }
场景2:a.txt本身为UTF-16 LE编码
修正内存分配、终止符位置,增加BOM跳过逻辑即可:
- 内存按字节数分配即可,额外多申请2字节存放终止空字符
- 实际读取完成后,根据
bytesRead计算实际宽字符数,在对应位置写入终止符 - 检查数组开头2字节是否为UTF-16 LE的BOM标识
0xFEFF,若存在则将输出指针向后偏移2字节跳过BOM
内容的提问来源于stack exchange,提问作者Nazarevsky
相关产品推荐
相关产品推荐

