C++读取UTF8带BOM的txt文件时字节缺失与行数不匹配问题求助
问题诱因分析
- 核心原因:默认采用文本模式打开文件,未指定
std::ios::binary标志- Windows平台下文本模式会自动将文件中的
\r\n换行序列转换为单个\n,每出现一次换行就会少读取1字节,你遇到的17000余字节差值刚好和文件1.7万左右的行数匹配 - 文本模式下
tellg()返回的是文本逻辑偏移量,不是文件实际物理字节数,和std::filesystem获取的物理文件大小本身就不匹配
- Windows平台下文本模式会自动将文件中的
- 行数不一致的原因:
- 调用
read未读满缓冲区时,你直接将未补\0结尾的裸char指针传递给stringstream,会读取到缓冲区之后的野内存,内存中随机出现的\n会被识别为换行符,因此v2的行数远大于实际行数,多出来的行都是无效的垃圾数据
- 调用
修复方案
- 打开文件时必须追加二进制模式标志:
二进制模式下不会做任何换行符转换,std::fstream data_file(path_to_file, std::ios::in | std::ios::binary);seekg/tellg返回的都是物理字节偏移,和实际文件大小完全对应 - 读取完数据转字符串处理时,必须根据实际读取的字节数初始化对象,不要直接使用裸char指针:
// 正确写法,避免读取野内存 std::stringstream ss(std::string(buffer, chars_read), std::ios::in); - 处理UTF8 BOM时,读取后判断前3字节是否为
0xEF 0xBB 0xBF,是的话跳过这3个字节再解析CSV内容即可 - 注意你的代码中
file_size变量如果遇到文件打开失败的情况会处于未初始化状态,建议定义时直接赋值初始值0避免未定义行为。
排查测试方法
- 追加二进制打开标志后重新测试
read的返回字节数,应该和文件物理大小完全一致 - 输出v2末尾的若干行内容,可验证多出来的行都是乱码/无效内容,确认野内存问题
- 用二进制编辑器打开原文件统计
\r\n的数量,可验证和字节差值的对应关系
内容的提问来源于stack exchange,提问作者Ben Andrews
相关产品推荐
相关产品推荐

