C++无法读取.dat文件中存储的vector类型数据问题求助
C++读取.dat文件中vector数据失败问题解决
核心问题原因
你当前代码的错误根源是直接对包含非POD类型(vector、string都属于非POD类型)的类对象做二进制读写操作:
vector和string内部仅存储指向堆内存的指针,实际的字符串、元素数据都存在堆空间- 你用
outfile.write(reinterpret_cast<char*>(this),sizeof(*this))写入的只是对象本身的内存数据,其中包含的是当前进程的堆指针地址,不是实际的元素内容 - 首次运行写入后立刻读取能正常显示,是因为当前进程里指针指向的堆内存还没释放,地址是有效的;下次重启进程后,之前写入的指针地址在新的进程空间里完全无效,自然读不到数据
修复方案
需要手动实现类的序列化/反序列化逻辑,不能直接读写整个对象:
- 写入时:先写入
vector的元素个数,再逐个写入每个string的长度、再写入字符串实际内容 - 读取时:先读
vector的元素个数,再逐个读每个string的长度、再读对应长度的字符串内容存入vector
修改后的可运行代码
#include<iostream> #include<vector> #include<string> #include<fstream> using namespace std; class Symptom { public: vector<string> symptomList; string symptom; const string fileName = "disease.dat"; char ch; // 序列化Symptom到文件 void serialize(ofstream& outfile) { // 先写symptomList的大小 size_t listSize = symptomList.size(); outfile.write(reinterpret_cast<char*>(&listSize), sizeof(listSize)); // 逐个写入每个symptom for (const string& s : symptomList) { size_t strLen = s.size(); outfile.write(reinterpret_cast<char*>(&strLen), sizeof(strLen)); outfile.write(s.c_str(), strLen); } } // 从文件反序列化Symptom void deserialize(ifstream& infile) { symptomList.clear(); // 先读symptomList的大小 size_t listSize; infile.read(reinterpret_cast<char*>(&listSize), sizeof(listSize)); // 逐个读取每个symptom for (size_t i = 0; i < listSize; i++) { size_t strLen; infile.read(reinterpret_cast<char*>(&strLen), sizeof(strLen)); string s(strLen, '\0'); infile.read(&s[0], strLen); symptomList.push_back(s); } } // 调用该方法添加疾病对应的症状列表 void addSymptom() { int i = 0; cout<<"输入疾病对应的症状:"<<endl; symptomList.clear(); do { // 插入每个症状到symptomList cout<<++i<<". "; getline(cin, symptom); symptomList.push_back(symptom); cout<<"是否要输入下一个症状?(y/n)"; cin>>ch; cin.get();// 配合循环内getline使用,清除换行符缓存 } while(ch=='y'||ch=='Y'); } // 展示该疾病的所有症状 void showSymptom() { cout << "症状列表:"<<endl; for (auto it = symptomList.begin(); it != symptomList.end(); ++it) cout << " - " << *it << endl; } }; class Disease { public: Symptom symptoms; const string fileName = "disease.dat"; // 添加疾病信息到文件 void addDisease() { char ch; ofstream outfile(fileName, ios::binary | ios::out); if(!outfile.is_open()) { cout<<"打开文件失败"; return; } // 先预留位置存储疾病总个数,后续写入完成后回来更新 size_t diseaseCount = 0; streampos countPos = outfile.tellp(); outfile.write(reinterpret_cast<char*>(&diseaseCount), sizeof(diseaseCount)); do { symptoms.addSymptom(); symptoms.serialize(outfile); diseaseCount++; cout<<"\n是否要输入下一个疾病的信息?(y/n)"; cin>>ch; cin.get(); } while(ch=='y'||ch=='Y'); // 回到文件开头更新疾病总数 outfile.seekp(countPos); outfile.write(reinterpret_cast<char*>(&diseaseCount), sizeof(diseaseCount)); outfile.close(); } // 从文件读取疾病信息 void getDisease() { ifstream infile(fileName, ios::binary); if(!infile.is_open()) { cout<<"打开文件失败"; return; } // 先读取疾病总数 size_t diseaseCount; infile.read(reinterpret_cast<char*>(&diseaseCount), sizeof(diseaseCount)); for (size_t i = 0; i < diseaseCount; i++) { symptoms.deserialize(infile); symptoms.showSymptom(); } infile.close(); } }; int main() { Disease d; // d.addDisease(); // 新增疾病信息 d.getDisease(); // 展示疾病信息 return 0; }
内容的提问来源于stack exchange,提问作者Nawaraj
相关产品推荐
相关产品推荐

