Question

I'm trying to understand how to properly right data to a binary file. The data is being written but when read back in for testing it is obvious I am not writing it properly. The data is read/written as follows.

Unsigned Char tells how long next string will be, then a string is written, and then an integer ID is written. ( or length studentname student_id ). The following is the printList function which saves the data to a file.

void printList(struct node * nptr, string filename){
  ofstream myfile;
  myfile.open( filename.c_str(), ios::binary );

  while(nptr){

  myfile.write( (char*) &nptr->data.len, sizeof( unsigned char ) );
  myfile.write( (char*) nptr->data.name, len * sizeof(char) );
  myfile.write( (char*) &nptr->data.id, sizeof(int) );

 //myfile.write( (const char*) &nptr->data, sizeof( Student ) );

 nptr = nptr->next;
}

myfile.close();

}

Here is the student struct from which the data is stored in a link list:

struct node{
Student data;
struct node* next;
};

//=== Student struct===//
 struct Student{
    unsigned char len;
char* name;
int id;
};
//====================//

Here is the loadbin file I wrote to read the binary back in, again I am messing something up and I have read and watched a ton of tutorials on this. I really am stumped.

unsigned char len;
char* name;
int id;

int main( int argc, char* argv[] )
{
    if( argc > 1 )
    {
        ifstream f( argv[1] , ios::binary);

        while( !f.eof() )
        {
            f.read( (char*) &len , sizeof( unsigned char ) );

            if( f.eof() )
                break;

        name = new char[len+1];
        name[len+1] = '\0';

        f.read( (char*) name , len * sizeof( char ) );
        f.read( (char*) &id , sizeof( int ) );

        cout << (int)len << " " << name << " " << id 
                                            << "\n";
        }
    }

   else
        cout << "\nToo few arguments.\n";

}

Some more info, I can't change how the file is being read back in. The fix has to come from when I'm writing. I just included that in case it would help.

Was it helpful?

Solution

For a start, I'm not even sure this should compile, unless you have a len variable floating around somewhere, such as in your last code segment:

myfile.write( (char*) nptr->data.name, len * sizeof(char) ); // len, what len?

Since sizeof(char) is always one and I prefer explicit expressions as much as possible, I'd rewrite the three output lines as:

myfile.write ((const char *)(&(nptr->data.len)), 1);
myfile.write ((const char *)(nptr->data.name), nptr->data.len);
myfile.write ((const char *)(&(nptr->data.id)), sizeof(int));

A full program showing how to use that follows, similar enough that it will help, but different enough so that you can't just hand it in as your own work :-)

#include <iostream>
#include <fstream>

struct Student {
    unsigned char len;
    char *name;
    int id;
};

struct node {
    Student data;
    struct node *next;
};

int main (void) {
    // Create dummy list, two nodes.

    node *temp = new node();
    temp->data.len = 6;
    temp->data.name = (char *)"diablo";
    temp->data.id = 2;
    temp->next = NULL;

    node *shortList = new node();
    shortList->data.len = 3;
    shortList->data.name = (char *)"pax";
    shortList->data.id = 1;
    shortList->next = temp;

    // Write it out.

    std::ofstream myfile;
    myfile.open ("xyzzy.bin", std::ios::binary);
    node *curr = shortList;
    while (curr != NULL) {
        myfile.write ((const char *)(&(curr->data.len)), 1);
        myfile.write ((const char *)(curr->data.name), curr->data.len);
        myfile.write ((const char *)(&(curr->data.id)), sizeof(int));
        curr = curr->next;
    }
    myfile.close ();

    return 0;
}

If you run that program then do a hex dump, you get:

addr  +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +a +b +c +d +e +f  0123456789abcdef
----  -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --  ----------------
0000  03 70 61 78 01 00 00 00 06 64 69 61 62 6c 6f 02  .pax.....diablo.
0010  00 00 00                                         ...
0013

which I think matches the format you wanted.

OTHER TIPS

Without some clue to the contents of the file, it is hard to debug, but try to ensure things are absolutely clear.

Rather than

  myfile.write( (char*) &nptr->data.len, sizeof( unsigned char ) );
  myfile.write( (char*) nptr->data.name, len * sizeof(char) );
  myfile.write( (char*) &nptr->data.id, sizeof(int) );

it is less error-prone to write (I squeezed out spaces to keep within line length):

  myfile.write((char*)&nptr->data.len, sizeof(nptr->data.len) );
  myfile.write((char*)nptr->data.name, nptr->data.len*sizeof(nptr->data.name[0]));
  myfile.write((char*)&nptr->data.id, sizeof(nptr->data.id) );

and use similar expressions to unpack the data when it is read back. Using sizeof on the variables is more robust than using type names.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top