Binary file reading/writing in C

40,917

Solution 1

Your structure definition is:

typedef struct foo
{
    char kid[7];    
    char jid[7];    
    char name[21];  
    char time[20];  
} Foo;

The code that writes the structures to the file is in write():

for (i = 0; i < jel_size; i++)
    fwrite(&foo[i], sizeof(struct foo), 1, f);

If the structures are intialized with all bytes zero, then for the first row of data you mention:

IK-SZH;jdl72u;John Doe;2013-03-28 11:05

we can infer that the structure contains:

IK-SZH\0
jdl72u\0
John Doe\0\0\0\0\0\0\0\0\0\0\0\0\0
2013-03-28 11:05\0\0\0\0

which more or less agrees with what you say the file contains:

IK-SZH NUL jdl72u NUL John Doe NUL NUL NUL NUL NUL 2013-03-28 NUL NUL NUL 

By my reckoning, you're missing a few NULs after the name and the time and one NUL after the date.

If you want text output, you will have to format the data in write() using fprintf() analogous to the fscanf() statement you have in the read() function. You should probably return a status from the function to indicate whether it was successful. You can argue for checking that fclose() was successful, too.

void write(void)
{
    FILE *fp = fopen("input.bin", "w");
    if (fp != 0)
    {
        for (int i = 0; i < jel_size; i++)
            fprintf(fp, "%s;%s;%s;%s\n", foo[i].kid, foo[i].jid, foo[i].name, foo[i].time);
        fclose(fp);
    }
}

If you want binary output, you should use binary input in read(). Again, you should consider returning an indication of success or failure; avoiding global variables is good, too.

void read(const char *filename)
{
    FILE *fp = fopen(filename, "rb"); 
    if (fp != 0)
    {
        for (i = 0; fread(&foo[i], sizeof(foo[i]), 1, fp) == 1; i++)
            ;
        fclose(fp);
        size = i;
    }
}

Either technique will work; trying to use one on output and the other on input is going to lead to chaos and confusion.

Note that functions read() and write() are used by POSIX with a different interface. While you stick with Standard C, the names are fair for you to use, but you'd probably be better off with alternative names, such as reader() and writer() or foo_read() and foo_write().

Solution 2

https://gist.github.com/anonymous/5288805

Changed code just a bit, commented, and also tested, so it works for sure.

Share:
40,917
vzkiss
Author by

vzkiss

Updated on July 09, 2022

Comments

  • vzkiss
    vzkiss almost 2 years

    So I have an input.bin file which contains the following

    IK-SZH;jdl72u;John Doe;2013-03-28 11:05
    IK-GRR;kat91n;Jane Doe;2013-03-21 15:41
    IK-GRR;oat62f;Jane Doe;2013-03-24 08:08
    

    What I am doing is to read it into a struct. Doing some stuff with the data. Add/Delete lines. Then i would like to write the content of the structure back to the input.bin file in the same format as above.

    But instead of appearing as it is above. It's like this (no spaces):

    IK-SZH NUL jdl72u NUL John Doe NUL NUL NUL NUL NUL 2013-03-28 NUL NUL NUL IK-GRR NUL kat91n NUL Jane Doe NUL NUL NUL NUL ...
    

    When I re-read the file (with the NULs) It only puts the 1st line into the struct

    My code

    typedef struct foo {
        char kid[7];    
        char jid[7];    
        char name[21];  
        char time[20];  
    
    } Foo;
    
    Foo foo[200];
    FILE* fp;
    int size;
    

    ------- File reader

    void read(char* filename){
        fp = fopen(filename, "rb"); 
        int i = 0;
    
        while (!feof(fp)) {
    
            if (fp==NULL){perror("File opening error\n"); exit(1);}
    
            fscanf(fp,"%[^;]; %[^;]; %20[^\;]; %s\n", foo[i].kid, foo[i].jid,
                    foo[i].name, foo[i].time);
            i++;
        }
    
        size = i;
    
        print();
    
        fclose(fp);
    }
    
    
    void print(){
        int i;
        for (i = 0; i < size; ++i){
            printf("%s\t %s\t %s\t %s\n", foo[i].kid, foo[i].jid,
                   foo[i].name, foo[i].time);
        }
    }
    

    ----- Writer

    void write(){
        char str[1000];
    
        FILE* f = fopen("input.bin", "wb");
        fseek(f, 0, SEEK_SET);
        int i;
        for (i = 0; i < jel_size; i++)
                fwrite(&foo[i], sizeof(struct foo), 1, f);
        fclose(f);
    
    }
    

    Tried this, but this didn't write anything to the file:

        char str[1000];
        sprintf(str,"%s;%s;%s;%s\n", jelent[i].kazon,
                        jelent[i].jazon,jelent[i].nev,  jelent[i].ido );
    
            write(f,&str,sizeof(str))!=sizeof(str);
    
  • vzkiss
    vzkiss about 11 years
    Can't believe i didn't think about fprintf. I have already known about the fread, fwrite thing. Just didn't want to use that as there are ; separators in the file and was not sure how to solve the problem with that. Thanks a ton for your help!