views:

277

answers:

3

I need to make a file that contains "name" which is a string -array of char- and "data" which is array of bytes -array of char in C++- but the first problem I faced is how to separate the "name" from the "data"? newline character could work in this case (assuming that I don't have "\n" in the name) but I could have special characters in the "data" part so there's no way to know when it ends so I'm putting an int value in the file before the data which has the size of the "data"! I tried to do this with code as follow:

if((fp = fopen("file.bin","wb")) == NULL)
{
    return false;
}
char buffer[] = "first data\n";
fwrite( buffer ,1,sizeof(buffer),fp );
int number[1];
number[0]=10;
fwrite( number ,1,1, fp );
char data[] = "1234567890";
fwrite( data , 1, number[0], fp );
fclose(fp);

but I didn't know if the "int" part was right, so I tried many other codes including this one:

char buffer[] = "first data\n";
fwrite( buffer ,1,sizeof(buffer),fp );
int size=10;
fwrite( &size ,sizeof size,1, fp );
char data[] = "1234567890";
fwrite( data , 1, number[0], fp );

I see 4 "NULL" characters in the file when I open it instead of seeing an integer. Is that normal? The other problem I'm facing is reading that again from the file! The code I tried to read didn't work at all :( I tried it with "fread" but I'm not sure if I should use "fseek" with it or it just read the other character after it.

I thought of using a class as following and then writing and reading it back:

class Sign
{
public:
char* name;
int size;
char* data;
};

but that was not an easy thing in C++ !!

I also tried the following:

void saveData(char* filename) {

    fstream filestr;
    int n;
    n=10;
    char* data= "1234567890";

    filestr.open (filename, fstream::out | fstream::binary);
    for (int j = 0; j<5 ; j++)
    {
       filestr << n;

       for (int i = 0; i < n; i++) {
            filestr << data[i];
       }
    }
    filestr.close();
}

void readData(char* filename) {
    fstream filestr;
    int n =0;

    filestr.open (filename, fstream::in | fstream::binary);
    int m =0;
    //while(!filestr.eof())
    while(m<5)
    {
        filestr >> n;

        char *data = new char[n];
        for (int i = 0; i < n; i++) {
            filestr >> data[i];
        }
        printf("data is %s\n",data);
        m++;
    }
    filestr.close();
}

but the reading didn't work either :( on reading I'm getting strange characters !!

Any suggestions and help is appreciated..

Forgive me but I'm a beginner :(

A: 

Well, a few issues with your code:

fwrite( buffer ,1,sizeof(buffer),fp );

The function is defined as this:

size_t fwrite ( const void * ptr, size_t size, size_t count, FILE * stream );

So you're sending the information in buffer, saying it has a size of 1, and count of sizeof(buffer). That might work for some things, but is just generally backwards. Try using:

fwrite(buffer, sizeof(char), strlen(buffer), fp);

That's both character-width independent and has no constant values you need to worry about (it will work for basically any string).

Another minor thing in this:

 int number[1];

You have a single integer, so you need only use:

 int number;

If you run into errors with fwrite after changing it, use this call:

fwrite( &number, sizeof(int), 1, fp);

That will write the value of one integer to the file.

After you fix that up, see if your code works. It will certainly be easier to troubleshoot with those calls corrected. :)

Also, if you're planning on using field lengths (written as ints into the file), you're going to want to set up some kind of system to read the length, then data, and you should probably have a length for each field. Using a class is definitely the easiest way to handle that.

Edit: You may want to use a struct and function instead of a class, or you could use a class with methods. It doesn't really matter, both are pretty simple. Struct/func:

struct Record
{
    std::string name, data;
};

void writeRecord(Record thisRecord, std::string filename, size_t offset)
{
    if ( ( fp = fopen(filename.c_str(), "wb") ) == NULL ) { return NULL; }

    fwrite( thisRecord.size(), sizeof(unsigned int), 1, fp); // assuming size() return uint
    fwrite( thisRecord.name.c_str(), sizeof(char), name.size(), fp);

    // repeat for data or other fields
    fclose(fp);
}
peachykeen
what's the difference between strlen(buffer) and sizeof(buffer) ?as for the intger, I still see "NULL""NULL""NULL" !Please can you tell me how to use a class in this case? I tried it but it didn't work, I think it's a little more complicated than what I did :(
Reem
Strlen(buffer) will count the number of characters in the buffer (eg, "aaa" will return 3). Sizeof(buffer) will return the number of bytes in the buffer. If you're using Unicode, one character can be two bytes, so the difference becomes significant.As for the integer, unless you have a huge number, expect one or two NULLs. In your file, the number 32 would write as 0x00 0x00 0x00 0x20.
peachykeen
+1  A: 

First, your writing / reading in binary format should work like this (here read_num would contain 10 after this reading sequence).

   FILE* fp = fopen("file.bin", "wb");
   int num = 10;
   fwrite(&num, sizeof(int), 1, fp);
   fclose(fp);

   FILE* fp2 = fopen("file.bin", "rb");
   int read_num;
   fread(&read_num, sizeof(int), 1, fp2);
   fclose(fp2);

Also to mention, this way of writing is not the C++ way, but is the C way. C++ way of file operations means streams, see the following sample:

#include <fstream>
#include <string>

struct data_structure {
   std::string name;
   std::string description;
   int number;

   void save(const std::string& filename) {
      std::ofstream file(filename.c_str());
      file << name.c_str() << std::endl
           << description.c_str() << std::endl
           << number;
   }
   void load(const std::string& filename) {
      std::ifstream file(filename.c_str());

      getline(file, name);
      getline(file, description);
      file >> number;
   }
};

int main() {
   data_structure d, loaded_d;
   d.name = "Name";
   d.description = "Description";
   d.number = 5;

   d.save("file.out");
   loaded_d.load("file.out");

   return 0;
}
Kotti
Thanks for the first part, it did work.But as for the second part, the problem is Description might be more than one line and might contain newline character inside it!
Reem
A: 

So far the code that works for me is this:

void saveData(char* filename) {
    fstream filestr;
    char * name = "first data\n";
    int n;
    n=10;
    char* data= "asdfghjkl;";

    filestr.open (filename, fstream::out | fstream::binary);
    for (int j = 0; j<5 ; j++)
    {
        filestr << name;
        filestr << strlen(data);
        filestr << data;
    }
    filestr.close();
}


void readData(char* filename) {
    fstream filestr;
    int n =0;

    filestr.open (filename, fstream::in | fstream::binary);
    while(!filestr.eof())
    {
        string name;
        getline(filestr,name,'\n');
        printf("name is %s\n",name.c_str());

        filestr >> n;

        char *data = new char[n];
        for (int i = 0; i < n; i++) {
            filestr >> data[i];
        }
        printf("n is%d\ndata is %s\n",n,data);
    }
    filestr.close();
}

but the problems in reading are:

1- (I don't think it's a real problem) it prints other characters in addition to the actual data. 2- on readData function I get the output 6 times (in the last time I get every field as an empty field) while I have written only 5 times! Anyone knows why is that? is that related to while(!filestr.eof()) ??

Thanks for help

Reem
My problem now is with reading not with writing :(When I try to read using `filestr >> data[i];` it doesn't read the " " space character or "\n" :(Please anyone can help with that!
Reem