Windows API ReadFile()每读取两个字符就跳过一个问题排查
问题根因
你遇到的字符丢失问题完全是代码里的编码逻辑错误导致的,和CreateFile、ReadFile接口本身无关,错误点如下:
- 你的
words.txt是单字节编码文本(ASCII/GBK/UTF-8无BOM均属于这类),每个字符占1字节,但你用双字节的WCHAR数组作为读取缓冲区,相当于把相邻2个单字节字符拼接成了1个WCHAR值。 - 后续你把
WCHAR数组转std::string时,默认只取每个WCHAR的低8位,高8位直接丢弃,正好对应每2个原始字符丢1个,完全符合你描述的HELLO变成HLO的现象。 - 额外冗余的多次编码转换(WCHAR转string又转回WCHAR)进一步放大了错误,完全没有必要。
修复方案
根据你的文本文件编码选择对应方案即可:
方案1:文件为单字节编码(ASCII/GBK/UTF-8)
直接用char数组承接读取的字节,再按编码规则转成WCHAR即可,修改后代码如下:
void init(HDC hdc) { HANDLE hFile; LPCSTR fileName = "c:\\Users\\kanaa\\Desktop\\code\\HW2_StarterCode\\words.txt"; hFile = CreateFileA(fileName, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); DWORD dwFileSize = GetFileSize(hFile, NULL); DWORD dwBytesRead; // 用char数组存单字节内容 char* buffer = new char[dwFileSize + 1]; buffer[dwFileSize] = 0; bool read = ReadFile(hFile, buffer, dwFileSize, &dwBytesRead, NULL); CloseHandle(hFile); if (read) { // 单字节转WCHAR,GBK编码用CP_ACP,UTF-8编码用CP_UTF8 int wlen = MultiByteToWideChar(CP_ACP, 0, buffer, dwFileSize, NULL, 0); WCHAR* wbuf = new WCHAR[wlen + 1]; MultiByteToWideChar(CP_ACP, 0, buffer, dwFileSize, wbuf, wlen); wbuf[wlen] = 0; parse(wbuf, hdc); delete[] wbuf; } delete[] buffer; } // parse可直接简化,不用再转码 void parse(const WCHAR* wcword, HDC hdc) { Graphics graphics(hdc); drawText(&graphics, wcword); }
方案2:文件为UTF-16LE编码(Windows下的Unicode格式)
无需转码,只需跳过开头的2字节BOM即可直接使用:
void init(HDC hdc) { HANDLE hFile; LPCSTR fileName = "c:\\Users\\kanaa\\Desktop\\code\\HW2_StarterCode\\words.txt"; hFile = CreateFileA(fileName, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); DWORD dwFileSize = GetFileSize(hFile, NULL); DWORD dwBytesRead; WCHAR* buffer = new WCHAR[dwFileSize / 2 + 1]; buffer[dwFileSize / 2] = 0; bool read = ReadFile(hFile, buffer, dwFileSize, &dwBytesRead, NULL); CloseHandle(hFile); if (read) { // 跳过UTF-16 LE的BOM头(0xFEFF) const WCHAR* text = buffer; if (buffer[0] == 0xFEFF) text++; parse(text, hdc); } delete[] buffer; }
内容的提问来源于stack exchange,提问作者kanayt
相关产品推荐
相关产品推荐

