无法读取Ubuntu中的.dat或.bin文件“Segmentation fault(核心转储)”

问题描述:

因此,我刚刚开始使用Ubuntu。 我正在构建这个非常简单的程序,它可以让我存储一些数据并在稍后读回。无法读取Ubuntu中的.dat或.bin文件“Segmentation fault(核心转储)”

使用C++,fstream,一些对象存储在.dat文件中。

// function to store 
void storeRecord(Record r){ 
    fstream afile; 
    afile.open("file.dat" , ios::out | ios::binary | ios::app); 
    afile.write(reinterpret_cast <const char*> (&r), sizeof(r)); 
    afile.close(); 
} 

但当我尝试(调用查询()函数)从同一个文件中读取,我得到“分割故障(核心转储)”

void query(){ 
     Record r; 
     fstream afile; 
     afile.open("file.dat", ios::in | ios::binary); 
     while(afile.read(reinterpret_cast <char*> (&r), sizeof(r))){ 
      // do something 
     } 
     afile.close(); 
} 

这用来工作在窗户上。这是为什么?

#include <iostream> 
#include <string> 
#include <fstream> 

using namespace std; 

class Record{ 
public: 
    // Constructors 
    Record(); 
    Record(string accountID, string name, string deptID, string password,   int role); 
    ~Record(); 

    // Assessors and Mutators 
    string getAccountID(); 
    string getName(); 
    string getDeptID(); 
    string getPW(); 
    int getRole(); 

    void setAccountID(string accountID); 
    void setName(string name); 
    void setDeptID(string deptID); 
    void setPW(string PW); 
    void setRole(int role); 

    // Other functions 
    string toString(); 

private: 
    string accountID; 
    string name; 
    string deptID; 
    string password; 
    int role;  // normal user, HR personal, admin 
}; 
+5

在查询中没有定义r。什么是记录?如果它不是POD,那么你有bug。 – 2017-10-17 17:39:44

+0

有。在实际的程序中。我的错误在这里。 oops – poh

+1

“Record”的类型是什么?它是否有一些[vtable](https://en.wikipedia.org/wiki/Virtual_method_table)或一些(甚至是不正确的或内部的)指针? **你的代码有[未定义的行为](https://en.wikipedia.org/wiki/Undefined_behavior)**,所以你很幸运,它在Linux上崩溃(并且*不幸*它出现在Windows上) .... –

您的Record包含std::string字段。

A string当然包含指针,并可能包含一些带有虚函数的内部数据(因此有一个vtable,这是一个隐藏的指针);那么这些数据就有了指针。并且string而不是 a POD(但是固定阵列的char将是例如像char name[48]; ....的字段)。

所以,你的代码有undefined behavior所以你是幸运的,它crashes在Linux(和倒霉说,“出现”,它在Windows上工作)......顺便说一句,当它是显然“运行”(例如上您的Windows)文件格式保持“未定义”,您将无法再读取由旧版本程序编写的数据文件(或甚至是由较旧或不同的编译器和C++标准库编译的相同源文件)。

Linux有ASLR;这可能可以解释为什么你有一个segmentation fault。顺便说一句,我猜测,如果您在相同的process(这对您不是特别有用)中编写和读取相同的数据文件,Linux可能不会崩溃。

要了解更多信息,您需要深入了解实施细节,而您不想。

显然,您需要实施一些serialization机械。然后指定首先(详细)你的file format(逐字节,endianness和“字大小”的问题和你的文件格式应该是“独立”的),也许使用一些EBNF表示法。然后执行序列化例程,从基本POD类型开始。或者使用一些序列化库。你的文件格式和代码应该是可移植的(例如,树莓派和Linux/PC上的相同程序应该能够交换数据文件)。

顺便说一句,我更喜欢使用一些文本格式,可能使用JSON,YAML(或XML)。或者考虑像SQLiteGDBM这样的库。在你的情况下,你的Record很容易映射到SQLite表中的行或JSON对象。也许你应该问你的老师是否允许使用它们......