You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用vector时无法读取文件中的C++类对象,求解决方法

解决VS2017中C++读取二进制文件类对象时的异常问题

兄弟,我看你在VS2017 Community里写C++代码的时候,遇到了读取文件里的Company类对象就抛异常的问题,我来帮你一步步分析解决!

先回顾下你的场景:你写了一个程序,支持写入类对象到二进制文件Ma.bin,或者从文件读取指定对象显示。但选择读取(选项1)时,执行File.read((char *)&Temp, sizeof(Temp))这行代码就会抛出异常,注释掉这行程序就能正常跑,对吧?

问题根源分析

我看了你的代码,发现几个关键问题,正是这些问题导致了异常:

  1. 变量作用域错误
    你在try块里声明了vector<Company> Object;,但catch块的作用域和try是相互独立的,所以catch里的Object.clear();、Object.push_back(Temp);这些代码其实都是非法的!编译器应该已经给你标红警告了吧?这种未定义行为很容易导致内存访问错误,直接触发异常。

  2. 类对象的二进制读写前提不满足
    直接用File.write/read配合sizeof(Company)读写类对象,要求Company必须是POD类型(Plain Old Data)。如果你的Company类里包含这些内容,绝对不能这么干:

    • std::string、std::vector这类标准容器
    • 动态分配内存的指针(比如char* companyName)
    • 虚函数(类里有虚函数就会有虚表指针,内存拷贝会破坏虚表)
    • 其他非POD类型的成员变量
  3. 文件操作的错误处理缺失
    你没有检查文件是否成功打开,比如如果Ma.bin不存在,File.open(...)会失败,后面的seekg、read操作都会直接出错。另外,计算对象总数的File.tellg() / sizeof(Company)也有问题:如果文件大小不是sizeof(Company)的整数倍,结果会出错,而且streampos和size_t的类型转换也可能导致意外。

  4. 输入合法性未校验
    你读取用户输入的对象编号时,没有检查编号是否在1到total之间,如果用户输入一个超出范围的数,会导致文件读取位置越界,直接触发异常。

一步步解决方法

1. 修正变量作用域

把vector<Company> Object;和fstream File;移到try块外面,让catch块能正常访问这些变量:

int main() {
    fstream File;
    Company Temp;
    vector<Company> Object; // 移到try块外,扩大作用域
    try{
        cout << " 1. Show Data ";
        cout << " 2. Put Data\n";
        cout << " => ";
        int a;
        cin >> a;
        cin.ignore(1000, '\n');
        if (a == 1) throw 5;
        
        Temp.Get_Data();
        Object.push_back(Temp);
        
        File.open("Ma.bin", ios::binary | ios::out | ios::app);
        if (!File.is_open()) {
            cout << "写入时打开文件失败!" << endl;
            return 1;
        }
        for (size_t i = 0; i < Object.size(); ++i) {
            File.write((char *)&Object[i], sizeof(Object[i]));
        }
        File.close();
    } catch (int) {
        Object.clear();
        File.open("Ma.bin", ios::binary | ios::in);
        if (!File.is_open()) {
            cout << "读取时打开文件失败!" << endl;
            return 1;
        }
        
        File.seekg(0, ios::end);
        streampos fileSize = File.tellg();
        if (fileSize % sizeof(Company) != 0) {
            cout << "文件损坏或格式不正确!" << endl;
            File.close();
            return 1;
        }
        auto total = fileSize / sizeof(Company);
        cout << " total Object write " << total << "\n";
        
        cout << " Which One you want to Display ?";
        int Number;
        cin >> Number;
        cin.ignore(1000, '\n');
        
        if (Number < 1 || Number > total) {
            cout << "无效的编号,请输入1到" << total << "之间的数!" << endl;
            File.close();
            return 1;
        }
        
        int Position = (Number - 1) * sizeof(Company);
        File.seekg(Position);
        File.read((char *)&Temp, sizeof(Temp));
        Object.push_back(Temp);
        File.close();
        
        auto It = Object.begin();
        It->Put_Data();
    }
    return 0;
}

2. 确保Company类是合法的POD类型(或实现序列化函数)

如果你的Company类包含非POD成员(比如std::string),那必须自己实现序列化和反序列化函数,不能直接内存拷贝。举个例子:

#include <string>
#include <fstream>
#include <iostream>
using namespace std;

class Company {
private:
    std::string name;
    int companyId;
public:
    void Get_Data() {
        cout << "输入公司名称:";
        getline(cin, name);
        cout << "输入公司ID:";
        cin >> companyId;
        cin.ignore(1000, '\n');
    }
    
    void Put_Data() const {
        cout << "公司名称:" << name << endl;
        cout << "公司ID:" << companyId << endl;
    }
    
    // 序列化到文件
    void writeToFile(std::fstream& file) const {
        // 先写字符串长度,再写字符串内容
        size_t nameLen = name.size();
        file.write(reinterpret_cast<const char*>(&nameLen), sizeof(nameLen));
        file.write(name.c_str(), nameLen);
        // 写入int类型的ID
        file.write(reinterpret_cast<const char*>(&companyId), sizeof(companyId));
    }
    
    // 从文件反序列化
    void readFromFile(std::fstream& file) {
        size_t nameLen;
        file.read(reinterpret_cast<char*>(&nameLen), sizeof(nameLen));
        name.resize(nameLen);
        file.read(&name[0], nameLen);
        file.read(reinterpret_cast<char*>(&companyId), sizeof(companyId));
    }
};

然后读写的时候就调用这些函数,替换原来的write/read:

// 写入时
for (const auto& comp : Object) {
    comp.writeToFile(File);
}

// 读取时
Temp.readFromFile(File);

3. 补充错误处理

上面的修正代码里已经加了文件打开检查、文件格式检查、输入合法性检查,这些能避免很多意外的异常。

异常截图

你提到的异常截图如下:
VS2017读取文件对象时抛出的异常

内容的提问来源于stack exchange,提问作者user9301263

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 10:07:16