C++二进制文件读写后触发访问违例异常问题排查
问题排查与解决步骤
1. 强制用二进制模式打开文件
Windows下文本模式会自动转换换行符,直接破坏二进制数据,必须指定二进制模式:
// 写入文件 std::ofstream out_file("cookies.bin", std::ios::binary | std::ios::out); // 读取文件 std::ifstream in_file("cookies.bin", std::ios::binary | std::ios::in);
如果之前用了默认的文本模式,数据会错位,读取后必然触发内存异常。
2. 修正字符串序列化逻辑
确保writeString和readString严格按「固定长度的数值+字符串内容」格式读写,用uint32_t做长度类型避免跨平台大小差异:
#include <cstdint> void writeString(std::ofstream& out, const std::string& str) { uint32_t len = static_cast<uint32_t>(str.size()); // 先写长度 out.write(reinterpret_cast<const char*>(&len), sizeof(len)); // 再写字符串内容 if (len > 0) { out.write(str.data(), len); } // 检查流状态,写入失败直接抛出错误 if (!out) { throw std::runtime_error("写入字符串失败"); } } void readString(std::ifstream& in, std::string& str) { uint32_t len = 0; // 先读长度 in.read(reinterpret_cast<char*>(&len), sizeof(len)); if (!in) { throw std::runtime_error("读取字符串长度失败"); } // 提前预留空间再读内容,避免内存越界 str.resize(len); if (len > 0) { in.read(str.data(), len); } if (!in) { throw std::runtime_error("读取字符串内容失败"); } }
之前的序列化函数大概率没处理流错误,或者用了int这种有符号类型,导致长度读取异常。
3. 结构体读写必须严格对应
假设你的Cookie结构体是这样的:
struct Cookie { std::string name; int expire_days; bool is_secure; };
写入时逐个序列化成员,还要先写元素总数:
void writeCookie(std::ofstream& out, const Cookie& cookie) { writeString(out, cookie.name); out.write(reinterpret_cast<const char*>(&cookie.expire_days), sizeof(cookie.expire_days)); out.write(reinterpret_cast<const char*>(&cookie.is_secure), sizeof(cookie.is_secure)); if (!out) { throw std::runtime_error("写入Cookie失败"); } } void writeCookies(std::ofstream& out, const std::vector<Cookie>& cookies) { uint32_t count = static_cast<uint32_t>(cookies.size()); // 先写元素个数,读取时才知道要读多少个 out.write(reinterpret_cast<const char*>(&count), sizeof(count)); if (!out) { throw std::runtime_error("写入Cookie总数失败"); } for (const auto& cookie : cookies) { writeCookie(out, cookie); } }
读取时严格按写入顺序和格式来:
void readCookie(std::ifstream& in, Cookie& cookie) { readString(in, cookie.name); in.read(reinterpret_cast<char*>(&cookie.expire_days), sizeof(cookie.expire_days)); if (!in) { throw std::runtime_error("读取过期天数失败"); } in.read(reinterpret_cast<char*>(&cookie.is_secure), sizeof(cookie.is_secure)); if (!in) { throw std::runtime_error("读取安全标记失败"); } } void readCookies(std::ifstream& in, std::vector<Cookie>& cookies) { uint32_t count = 0; in.read(reinterpret_cast<char*>(&count), sizeof(count)); if (!in) { throw std::runtime_error("读取Cookie总数失败"); } // 提前预留空间,避免多次扩容导致的内存问题 cookies.reserve(count); for (uint32_t i = 0; i < count; ++i) { Cookie cookie; readCookie(in, cookie); cookies.push_back(cookie); } }
绝对不能直接读写整个结构体,std::string内部存的是指针,写入文件后指针会变成野指针,读取后必然触发内存访问错误。
4. 避免手动关闭文件
不要手动调用close(),让std::fstream的析构函数自动处理——手动关闭时触发异常,本质是vector里的元素内存已经损坏,析构时访问了野指针。
5. 排查内存越界
用Visual Studio的内存检测工具或者Valgrind定位:
- VS里启用
_CRTDBG_MAP_ALLOC,程序退出前调用_CrtDumpMemoryLeaks(),查看是否有内存越界。 - 读取后打印每个
Cookie的字符串长度和内容,看是否有乱码或长度异常。
内容的提问来源于stack exchange,提问作者Mihai
相关产品推荐
相关产品推荐

