Read objects saved in.dat file

Asked

Viewed 1,501 times

3

How should I proceed so that the reading function can read the arquivo.dat Every time I start the program? I am recording objects in a file, and I need to read them whenever the program starts.

Problem: I am having segmentation failure problems while 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();

}
  • The problem is not so simple and you did not give accurate information, so I gave an answer that may help to find the way but I do not guarantee that it is the definitive solution.

3 answers

2


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

In fact you’re trying to make a serialization when you use the cast (char *) but it doesn’t give the result you expect.

In general you should save this data as text. Not that it cannot be binary, but you will have to create a format for this binary. It is not only throw any information there. In the text also needs a format but there is easier because it has some obvious and simple to manipulate.

Just because a file is considered binary does not mean that you can play binary code or direct information from memory. This binary means that the data there should be processed byte to byte and not consider there is anything specific in it. It should be treated as a sequence of bytes and the program must know how to treat them.

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

As C++ does not have its own functionality in its library that facilitates serialization. There are third-party libraries for this.

The first recommendation I make is to write in text file. Unless you really need it to be binary and you want to afford the complexity of doing this.

The second is to prepare a form if serialization to record and deserialization after reading.

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

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

Is it complicated? Yeah. Is there a better way? I don’t know.

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

The error occurs because deep down you are throwing dirt in memory.

The cast that you used is not recommended in C++. I’m not saying it will work but it would have helped if you had done reinterpret_cast<const char*>(&writer). I have no way to test here but I don’t know if the same would apply to reader. That’s just an idea.

I’m not saying what you’re doing can’t work, just that it’s a beautiful gambit. I’ll even suggest a change that might solve your situation if the guy DateAdress is simple enough. Note that it can work but is a fragile solution.

Read the data individually instead of reading the whole 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 guy, I kicked three names into the fields.

But also to work it might be necessary to "compact" the structure, which is not always desirable. I never did but I know that you need to use a #pragma:

GCC:

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

Microsoft:

#pragma pack(push, 1)
struct nome { ... };
#pragma pack(pop)
  • Buddy, thanks for the info! This method I used didn’t work with the type of project I’m doing, I chose to keep the Dateadress object, but in writing I’m writing it as Ios::out | Ios::app | Ios::Binary, in a same file, the files will be saved in a DATA directory, because I need to do searches through addresses provided by the user. Thanks again so much!

  • I did not understand what you meant by that. Or I understood and I think it is now clearer that you are on the wrong track.

  • I’ll post how I’m working now with the new version of the project.

0

The error is that you are not saving an object of the type DateAddress in the file, but actually a pointer to a DateAddress.

Your file .dat is getting something like:

A4 FE 22 00

4 bytes representing only one pointer to one DateAddress, or is the local variable writer.

So on the lines where you have:

ObjectWriter.write((char *)&writer, sizeof(writer));
ObjectReader.read((char *)&reader, sizeof(reader));

Should be:

ObjectWriter.write((char *)writer, sizeof(DateAddress));
ObjectReader.read((char *)reader, sizeof(DateAddress));

Still the above code makes a very "blind" reading/writing of file data, I think it would be more correct to read/write member by class member.

  • the problem is that my program tried to read something that was no longer in my memory, and I already knew this was happening I just wanted to see if there was any solution to do such a thing.

  • Exactly, because you were recording a pointer and not the DateAddress actually, when you read back the pointer was invalid, because it belonged to the previous execution of the program and it had already been destroyed.

  • exactly comrade ! hehehee.

0

void DataManip::DataManipWrite(DateAdress *writer) {

#define LENGTH 1024
char Directory[LENGTH] = {"Data/"}; 

    ofstream ObjectWriter;
    strcat(Directory, writer->getFamily()); strcat(Directory,".dat");
    ObjectWriter.open(Directory, ios::out | ios::app | ios::binary);    
    ObjectWriter << "#------------------------------#"<< endl;
    ObjectWriter << "Bairro: " << writer->getBairro() << endl;
    ObjectWriter << "Rua: " << writer->getRua() << endl;
    ObjectWriter << "Telefone: " << writer->getTelefone() << endl;
    ObjectWriter << "Numero: " << writer->getNumero() << endl;
    ObjectWriter << "#------------------------------#\n"<< endl;

    ObjectWriter.close();

}

void DataManip::DataManipRead(char Directory[]) {
    string line_text;
    ifstream ObjectReader;
    strcat(Directory,".dat");
    ObjectReader.open(Directory, ios::in | ios::binary);

    if(ObjectReader.is_open() ) {
        while(getline(ObjectReader, line_text)) {
            cout << line_text << endl;
        }

    }   

    ObjectReader.close();

}
  • Thanks for the personal information! for my project, I opted for this method.

  • I mean, you did what I told you?

  • i already had this version of the project more basically yes so I voted in his answer :P, I just wanted to know if there was any way to read similar objects we do with struct in C , for this type of project would not fit.

  • 1

    This is your solution or a supplement to the question?

  • 1

    a solution I already had for my project.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.