Windows下C++读取含ASCII 26字符文件失败的解决方案咨询
问题分析与解决方案
你的问题核心在于文本模式文件流对特殊控制字符的处理:十进制26对应的ASCII字符是SUB(替换字符,十六进制0x1A),在Windows的文本模式下,这个字符会被当作EOF标记,导致读取流提前终止,进而拿到无效数据。
一、序列化库是如何处理这类值的?
主流序列化库(比如Protobuf、Boost.Serialization、nlohmann/json等)解决这个问题的核心思路是强制使用二进制模式读写数据,同时避免文本模式的字符转换逻辑:
- 它们在打开文件时会明确指定
std::ios::binary标志,让操作系统原封不动地处理所有字节,不会把0x1A这类控制字符当作EOF。 - 部分库还会额外处理字节序(大端/小端),保证序列化后的数据能在不同架构的机器上正确反序列化,但最基础的保障就是二进制模式的流操作。
- 另外,这些库不会依赖文本输出/输入操作符(比如
<</>>),而是直接用底层的write()/read()方法来读写原始字节,避免任何隐式的字符处理。
二、如果坚持用自己的序列化方式,怎么正确读写?
只需要修改两个关键地方,就能让你的代码正常工作:
1. 用二进制模式打开文件
无论是写入还是读取,都要在打开流时加上std::ios::binary标志,禁用Windows文本模式的特殊处理:
修改后的写入代码
std::string filename = "D:\\Hello.txt"; size_t OriNumber = 26; // 打开时指定二进制模式 std::ofstream ofs(filename, std::ios::binary); // 直接用write写入原始字节,不要用string中转+<<操作符 ofs.write(reinterpret_cast<const char*>(&OriNumber), sizeof(OriNumber)); ofs.close();
修改后的读取代码
std::string filename = "D:\\Hello.txt"; size_t DeserializedNumber; // 同样用二进制模式打开 std::ifstream ifs(filename, std::ios::binary); // 直接用read读取对应字节数 ifs.read(reinterpret_cast<char*>(&DeserializedNumber), sizeof(DeserializedNumber)); // 检查读取是否成功 if (ifs.good()) { std::cout << DeserializedNumber << std::endl; } else { std::cerr << "读取失败:可能文件不存在或字节数不足" << std::endl; } ifs.close();
额外说明
你原来的代码用std::string存储字节再用<<写入,还有个潜在问题:<<是文本输出操作,即使在二进制模式下,它依然会按照字符串的逻辑处理。直接用write()写入原始字节是更可靠的方式。
内容的提问来源于stack exchange,提问作者van con Nguyen
相关产品推荐
相关产品推荐

