Saving in binary files

May 30, 2020 at 7:19pm
So what I'm trying to do is to save a linked list, like the one bellow, in a binary file so in case that the program crashes or something, I don't have to re-add all the nodes that I previously added, the thing is I don't have the slightest clue on how to do this

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
#include <iostream>
#include <string>

using namespace std;

class product_node
{
public:
    string name;
    string brand;
    unsigned int productCode;
    unsigned int typeCode;
    double price;
    unsigned int stock;
    unsigned int minStock;
    unsigned int maxStock;


    product_node* next;
};

class product_list
{


public:
    product_node* head;
    product_list()
    {
        head=NULL;
    }
    ~product_list()
    {
            no_produtos *current, *next;
            atual=head;
            while(current!=NULL)
            {
                next=current->next;
                delete current;
                current=next;
            }
    }

    void addProduct(unsigned int productCode, string name, string brand, 
    unsigned int typeCode, double price, unsigned int minStock,unsigned int 
    maxStock,unsigned int stock);
    
    void writeList();
   
};
May 30, 2020 at 9:14pm
Assuming you have a list where you could iterate over, then your code for writing to a binary file could look like:
1
2
3
4
5
    std::ofstream ofs("list.bin");
    for ( auto & item : my_list )
    {
        ofs.write( (char*)&item, sizeof(item) );
    }


see https://en.cppreference.com/w/cpp/io/basic_ostream/write
May 30, 2020 at 10:15pm
How can i apply hero to my list, do i have to do one of those loops for each variable in the node? And im guessing that id also need to do it for each node in the list.
how about reading from the file?
May 30, 2020 at 10:25pm
then your code for writing to a binary file could look like

Not in this case because of those two C++ strings in the node class.

Also you should start using C++ style casts, they are safer (if one can say any cast is safe).

how about reading from the file?

If you must use binary files, I recommend you start by getting the "writing" correct. But if binary files are not a "must use" you should really consider sticking with normal text files.


May 30, 2020 at 11:07pm
unfortunately binary files are required haha, i also dont know how to do the writing
May 30, 2020 at 11:09pm
should it be something like this?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Node* current = head;
FILE* fp = fopen("save.bin", "wb");

while (current != NULL) {
    fwrite(&current->code, sizeof(int), 1, fp);
    fwrite(&current->price, sizeof(double), 1, fp);

    // The string (plus the null byte)
    fwrite(current->name.c_str(), sizeof(char), current->name.length() + 1, fp);
    // newline to indicate new node
    if (current->next != NULL)
        fprintf(fp, "\n");

    current = current->next;
}

fclose(fp);
May 30, 2020 at 11:58pm
The trick is to create read() and write() methods for the little things, and build up to the big things.

Always write the read() and write() methods as a pair. Whatever is written by write() should be readable by read():
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
// Read and write a string
bool readString(istream &is, string &str)
{
    // a string is the size followed by the data
    size_t sz;
    is.read(reinterpret_cast<char*>(&sz), sizeof(sz));
    str.resize(sz);
    is.read(const_cast<char*>(str.data()), sz); // might not be portable
    return is.good();
}

bool writeString(ostream &os, string &str)
{
    // a string is the size followed by the data
    size_t sz = str.size();
    os.write(reinterpret_cast<char*>(&sz), sizeof(sz));
    os.write(const_cast<char*>(str.data()), sz); // might not be portable
    return os.good();
}

// Read and write a node. This does NOT change the next pointer
bool product_node::read(istream &is)
{
    readString(is, name);
    readString(is, brand);
    is.read(reinterpret_cast<char*>(&productCode), sizeof(productCode));
    // ADD CODE TO READ THE OTHER MEMBERS
    return is.good();
}

bool product_node::write(ostream &os)
{
    writeString(os, name);
    writeString(os, brand);
    os.write(reinterpret_cast<char*>(&productCode), sizeof(productCode));
    // ADD CODE TO WRITE THE OTHER MEMBERS
    return os.good();
}


// Read and write a list. Each node is written as a bool (true), followed'
// by the record. When bool is false, that indicates the end of the list.
bool product_list:read(istream &is)
{
    // ADD CODE TO READ THE LIST. Use product_node::read() to read
    // individual records
    return is.good();
}

bool product_list::write(ostream &os)
{
    // ADD CODE TO READ THE LIST. Use product_node::write() to write
    // individual records
    return os.good();
}


May 31, 2020 at 12:34am
But remember if your class has non-trivial constructed member variables you must write out each member variable one at a time. For example you can't directly write a std::string, you must first write the "length" of the string, then write the std::string.c_str() of that variable. Remember that a std::string is not a fixed length, and the data is "hidden" in basically as a pointer. So if you just write the std::string you actually write out a pointer, not the actual data.

May 31, 2020 at 12:36am
josilva00, could you tell why it's not allowed to do reading and writing in text mode? That makes no sense to me, at least not for your data that you have to store.
May 31, 2020 at 2:58am
you can't directly write a std::string, you must first write the "length" of the string, then write the std::string.c_str() of that variable.

I got bit by that when I was converting an older "save C string data" bit of code to "save std::string" by just writing the std::string to the file. It worked to save and retrieve some test data, until I changed the data. *CRASH, BANG, BOOM* Ooops!
May 31, 2020 at 9:41am
nuderobmonkey, this is part of a school project that I'm working on, Its already done, but I can get extra points if I manage to save in binary files
May 31, 2020 at 10:37am
dhayden, i think i've managed to write to the file, here is the code
1
2
3
4
5
6
7
8
9
10
product_list::write(ostream &os)
{
    product_node*current=head;
    while(current!=NULL)
    {
        current->write(os,current->name,current->brand,current->productCode,current->typeCode,current->price,current->stock,current->minStock,current->maxStock);
        current=current->next;
    }
    return os.good();
}


How do i read and fill the the list?


Edit:i opened the binary file after writing to it and its empty
Last edited on May 31, 2020 at 10:48am
May 31, 2020 at 12:34pm
i opened the binary file after writing to it and its empty
Did you close the output file before opening the input file? Did product_list::write() return true?

How do i read and fill the the list?
You can't with that write() code because there's no way to tell when you hit the end of the list. That's why my read() method had this comment:
1
2
// Read and write a list. Each node is written as a bool (true), followed
// by the record. When bool is false, that indicates the end of the list. 


You need to write the bool. That way when you're reading the list, you know when to stop.

An alternative is to make one pass through the list, counting the items. They write the count, followed by all the items (without the bool). When reading , you read the count, and then read exactly that many items.

Oh, and a bonus: when reading the list, you should clear any contents in it first.
May 31, 2020 at 12:56pm
i opened the binaryfile.bin, its size is 0kb and its empty after i use the write method
May 31, 2020 at 1:24pm
I've managed to make it work, to write and read back and add the nodes, just one question, how do i clear a binary file before writing to it?
May 31, 2020 at 5:11pm
Just open if for writing. That will clear it automatically.
Topic archived. No new replies allowed.