How can I write a structure to a file ?

17,202

Solution 1

There are two answers:

  1. It does work, if everything is set correctly and porting the written data to other machines is not an issue.
  2. It doesn't work if you have any of a large number of common features in data structures, or if you need to move the data from one type of machine (say an Intel machine) to another type (say PowerPC or SPARC).

In your example structure, you have no pointers, so you could write the structure verbatim to a file, and then in another invocation of the program running on the same (type of) machine, you could read it back in, and you would see the same data.

However, if your structure contained pointers, you could not meaningfully write the structure to disk. The pointers in one invocation of the program need not have any significance in another invocation of the program. If you needed to port the data between a little-endian (Intel) and big-endian (PowerPC, SPARC) machine, you'd have to use a platform-neutral way of accessing the data; simply writing the data to disk would not work.


So, where portability is not an issue, this code should work — Unix or Windows. It uses the "wb" and "rb" arguments to fopen() because the data is binary data, not plain text. The b is optional but harmless on Unix; it is crucial on Windows. The code also fixes the file name to sampledata.bin so it can be run on either platform, writing in the current directory. It writes the data; it then reads the data; it then compares the read data with the written data, reporting any problems. If the program says nothing, all is OK.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

struct emp
{
    char name[15];
    int age;
    int salary;
    char address[30];
};

int main(void)
{
    char const filename[] = "sampledata.bin";
    struct emp emp1[5] =
    {
        { "Yoda",  23, 45000, "Asia"      },
        { "Darth", 34,  2344, "N America" },
        { "Jabba", 22,  5566, "Africa"    },
        { "Luke",  33,  3399, "S America" },
        { "Leia",  44,  6677, "Europe"    },
    };
    struct emp emp2[5];
    FILE *ifp;
    FILE *ofp;
    int i;

    ofp = fopen(filename, "wb");
    if (ofp != 0)
    {
        if (fwrite(emp1, sizeof(emp1), 1, ofp) != 1)
        {
            fprintf(stderr, "Failed to write to %s\n", filename);
            exit(1);
        }
        fclose(ofp);
    }

    ifp = fopen(filename, "rb");
    if (ifp != 0)
    {
        if (fread(emp2, sizeof(emp2), 1, ifp) != 1)
        {
            fprintf(stderr, "Failed to read from %s\n", filename);
            exit(1);
        }
        fclose(ifp);
    }

    for (i = 0; i < 5; i++)
    {
        if (emp1[i].age != emp2[i].age ||
            emp1[i].salary != emp2[i].salary ||
            strcmp(emp1[i].name, emp2[i].name) != 0 ||
            strcmp(emp1[i].address, emp2[i].address) != 0)
            printf("Difference in record %d\n", i);
    }

    return 0;
}

Content of the file sampledata.bin:

0x0000: 59 6F 64 61 00 00 00 00 00 00 00 00 00 00 00 00   Yoda............
0x0010: 17 00 00 00 C8 AF 00 00 41 73 69 61 00 00 00 00   ........Asia....
0x0020: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   ................
0x0030: 00 00 00 00 00 00 00 00 44 61 72 74 68 00 00 00   ........Darth...
0x0040: 00 00 00 00 00 00 00 00 22 00 00 00 28 09 00 00   ........"...(...
0x0050: 4E 20 41 6D 65 72 69 63 61 00 00 00 00 00 00 00   N America.......
0x0060: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   ................
0x0070: 4A 61 62 62 61 00 00 00 00 00 00 00 00 00 00 00   Jabba...........
0x0080: 16 00 00 00 BE 15 00 00 41 66 72 69 63 61 00 00   ........Africa..
0x0090: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   ................
0x00A0: 00 00 00 00 00 00 00 00 4C 75 6B 65 00 00 00 00   ........Luke....
0x00B0: 00 00 00 00 00 00 00 00 21 00 00 00 47 0D 00 00   ........!...G...
0x00C0: 53 20 41 6D 65 72 69 63 61 00 00 00 00 00 00 00   S America.......
0x00D0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   ................
0x00E0: 4C 65 69 61 00 00 00 00 00 00 00 00 00 00 00 00   Leia............
0x00F0: 2C 00 00 00 15 1A 00 00 45 75 72 6F 70 65 00 00   ,.......Europe..
0x0100: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   ................
0x0110: 00 00 00 00 00 00 00 00                           ........
0x0118:

Solution 2

You don't specify what you mean by fwrite doesn't work, but I'll assume you're working on Windows, in which case you need to specify "wb" to fopen. By default on Windows, it's writing in text mode (i.e. "wt").

Solution 3

not a good idea to write struct to file or sockets as it is. It is inviting complex to solve problems. the best approach is to use serialization before writing. Also, as Jim pointed out above, make sure to open the file in binary.

Take a look in this question and the answers. there is a pretty good answer and explanation for your question. Passing a structure through Sockets in C

Share:
17,202
CP3O
Author by

CP3O

Updated on June 04, 2022

Comments

  • CP3O
    CP3O almost 2 years

    I have tried to look this up in multiple places and I cannot understand why fwrite doesn't work.

    If I had a structure with 100 fields I would not want to use fprintf with 100 format specifiers.

    struct emp
    {
          char name[15];
          int age;
          int salary;
          char address[30];
    };
    
    
    int main()
    {
    
        char str[60];
        struct emp emp1[5] = {{"Yoda",23,45000,"Asia"},{"Darth",34,2344,"NAmerica"},{"Jabba",22,5566,"Africa"},{"Luke",33,3399,"SAmerica"},{"Laya",44,6677,"Europe"}};
    
        FILE *fp;
        fp = fopen("C:/.../sampleText.txt","w");`
        int i=0;
       for(i=0; i<5; i++)
       {
    
                fwrite(&emp1[i],sizeof(emp1[i]),1,fp);
    
               //fprintf(fp,"%s, %d, %d, %s\n",&emp1[i].name,emp1[i].age,emp1[i].salary,emp1[i].address);
        }
    
        fclose(fp);
        getch();
     }