c++ – Read objects saved in .dat file

Question:

How should I proceed so that the read function can read the arquivo.dat whenever I start the program? I'm writing objects to a file, and I need to read them whenever the program starts.

Problem: I am having segmentation fault issues when trying to read this already saved data.

void DataManip::DataManipWrite(DateAdress *writer) {

    ofstream ObjectWriter;
    ObjectWriter.open("dbaddress.dat", ios::binary);    
    ObjectWriter.write((char *)&writer, sizeof(writer));
    ObjectWriter.close();

}

void DataManip::DataManipRead(DateAdress *reader) {

    ifstream ObjectReader;
    ObjectReader.open("dbaddress.dat", ios::binary);    
    ObjectReader.read((char *)&reader, sizeof(reader));
    ObjectReader.close();

}

Answer:

You cannot write objects and then read them into memory. You need to serialize them.

In fact you are trying to do a serialization when using cast (char *) but it doesn't give the result you expect.

In general you should write this data as text. Not that it can't be binary, but you'll have to create a format for that binary. It's not just throwing any information there. In the text you also need a format but then it's easier because there are some obvious and simple to manipulate.

Just because a file is considered binary doesn't mean you can dump binary code or information straight from memory. This binary means that the data there must be treated byte by byte and not consider there to be anything specific in it. It must be treated as a sequence of bytes and the program must know how to handle them.

In a text file there are some assumptions such as the existence of a line break.

As C++ doesn't have a feature of its own in its library that facilitates serialization. There are third party libraries for this.

The first recommendation I make is to save to a text file. Unless you really need it to be binary and want to deal with the complexity of doing this.

The second is to prepare a serialization form for writing and deserialization after reading.

The first will take each member of the DateAdress type and transform it into a sequential text that can be written to the file. Note that it may be necessary to do some conversions to numeric types and especially to types that are actually pointers. You cannot record the pointer, you will have to record the data that the pointer points to (this includes a recursive process) or some identification so that one piece of information is then correctly associated with another (this is not easy to do correctly).

When reading this data serialized in the file, you will have to do the reverse process, interpret each information contained in the text according to its size or through special markers (if you keep the order of the fields), or who know identifiers for each field (then you don't need to keep order, an example of this is the JSON format). Taking each piece of information individually, you can put it in the appropriate member of the DateAdress type, making the necessary conversions.

It is complicated? IT'S. Is there a better way? I do not know.

I just want to emphasize that eventually a binary file can be more useful, the big difference is that you'll have to understand the content without any help from the standard adopted in texts.

The error occurs because deep down you're playing dirt on memory.

The cast you used is not recommended in C++. I'm not saying it will work but it would help if I did reinterpret_cast<const char*>(&writer) . I can't test it here but I don't know if the same would apply to the reader . This is just an idea.

I'm not saying what you're doing can't work, just that it's a hell of a knick-knack. I'll even suggest a change that might solve your situation if the DateAdress type is simple enough. Note that it may work but it is a fragile solution.

Read data individually instead of reading the entire structure:

ObjectReader.read((char *)&reader.campo1, sizeof(reader.campo1));
ObjectReader.read((char *)&reader.campo2, sizeof(reader.campo2));
ObjectReader.read((char *)&reader.campo3, sizeof(reader.campo3));

Since I don't know the composition of the type, I guessed three names for the fields.

But also to work it may be necessary to "compress" the structure, which is not always desirable. I've never done it but I know it's necessary to use a #pragma :

GCC:

struct __attribute__((packed)) nome { ... };

Microsoft:

#pragma pack(push, 1)
struct nome { ... };
#pragma pack(pop)

I put it on GitHub for future reference .

Scroll to Top
AllEscort