Search code examples
carraysstructfwritefread

fread only reading in from the first time I ran the program


When I first run I would add 3 records, which gives me a count of 3. Then I fwrite the count into a bin file, and the records into a bin file, then I close the program.

When I reopen it and then I fread in and it will give me my 3 records and a count of 3. But from there on, no matter if I back up or when I read in, it will give me the same count 3 and 3 records, though since the count isn't being updated either this may be why fread is only reading in the first time records.

I am not sure why the counter isn't updating. Both fread and fwrite are returning = success so I am not sure what`s up.

void backUp(PAYROLL employee[], long int *pCounter)
{
    FILE *counter;
        errno_t result1 = fopen_s(&counter, "c:\\myFiles\\counter.bin", "a+b");
        if (result1 == 0){
            fwrite(pCounter, sizeof(long int), 1, counter);
            fclose(counter);
        }
        else
            printf("Back up of counter failed! error:%d",result1);

    FILE *record;

        errno_t result2 = fopen_s(&record, "c:\\myFiles\\record.bin", "a+b");
        if (result2 == 0){
            fwrite(employee, *pCounter *sizeof(PAYROLL), 1, record);
            fclose(record);
        }

        else
            printf("Back up of record failed! error:%d", result2);
}

void upload(PAYROLL employee[], long int *pCounter)
{
    FILE *counter;
    errno_t result1 = fopen_s(&counter, "c:\\myFiles\\counter.bin", "a+b");
    if (result1 == 0){
        result = fread(pCounter, sizeof(long int), 1, counter);
        fclose(counter);
        printf("Counter:%d", *pCounter);
    }
    else
        printf("Upload up of counter failed!");
    FILE *record;
    errno_t result2 = fopen_s(&record, "c:\\myFiles\\record.bin", "r+b");
    if (result2 == 0)
    {

            result2 = fread(employee, *pCounter *sizeof(PAYROLL), 1, record);
            printf("Upload successful!\n");

        fclose(record);
    }
    else
        printf("Error opening file!");
}

Solution

  • Transferring the most salient comments into an answer.

    Weathervane commented:

    How do you know that fread and fwrite are returning "success" when you have not checked their return value?

    Jude commented:

    I look through the debugger and step in to the function, result is giving me their success return values (if that's how it works).

    Weathervane commented:

    You still need that in the program. Without that sort of checking, your code will be blown over by a puff of wind.

    Dmitri correctly observed:

    Looks like everywhere you open in append mode "a+b" you should probably be using something else ("rb" in upload() and "wb" in backUp() possibly?)

    Jude commented:

    I don't understand, is there a specific function for error checking? As I had always thought that error checking was just looking at what goes in the value of result and then I can go check what the value means?

    Look at the specification of fread() and fwrite(). They return the number of records written or read, which may be less than the number requested. If you get a short write, then you have a problem — maybe out of disk space. If you get a short read, it may be that you requested 100 records but there were only 1 or 10 or 99 available to read (or there was an error). If you don't capture and check the return value, you've no idea what happened.

    Jude commented:

    I see they read and write 1, but it still stores the first 3 elements of my struct array. I assume it's one because it's only writing my array?

    fread() (and fwrite() too) give you considerable flexibility because you can supply the size of an item and the number of items separately. You use:

    result2 = fread(employee, *pCounter *sizeof(PAYROLL), 1, record);
    

    This tells fread() to read 1 item of size *pCounter * sizeof(PAYROLL). You will get a result of 1 (success) or 0 (failure). You could have specified:

    result2 = fread(employee, sizeof(PAYROLL), *pCounter, record);
    

    which would tell you how many records of size sizeof(PAYROLL) were read, up to a maximum of the value in *pCounter. You might get 0 or 1 or …

    Here is some workable code that does more or less what's required. The main() program demonstrates working with 1, 2 and 3 records (and the names are a few kings and queens of England, along with the year of their ascension to the throne as their employee ID number). I had to create a minimal payroll structure since the question didn't provide one.

    #include <stdio.h>
    #include <string.h>
    #include <errno.h>
    
    typedef struct PAYROLL
    {
        long emp_id;
        char emp_name[32];
    } PAYROLL;
    
    static const char counter_bin[] = "counter.bin";
    static const char records_bin[] = "records.bin";
    
    static
    void backUp(PAYROLL employee[], long int *pCounter)
    {
        FILE *counter = fopen(counter_bin, "wb");
        if (counter != 0){
            fwrite(pCounter, sizeof(long int), 1, counter);
            fclose(counter);
        }
        else
            fprintf(stderr, "Back up of counter failed! error: %d %s\n", errno, strerror(errno));
    
        FILE *record = fopen(records_bin, "wb");
        if (record != 0){
            fwrite(employee, *pCounter *sizeof(PAYROLL), 1, record);
            fclose(record);
        }
        else
            fprintf(stderr, "Back up of records failed! error: %d %s\n", errno, strerror(errno));
    }
    
    static
    void upload(PAYROLL employee[], long int *pCounter)
    {
        FILE *counter = fopen(counter_bin, "rb");
        if (counter != 0){
            size_t result = fread(pCounter, sizeof(long int), 1, counter);
            fclose(counter);
            if (result != 0)
                printf("Counter: %ld\n", *pCounter);
            else
                fprintf(stderr, "Failed to read counter\n");
        }
        else
            fprintf(stderr, "Upload up of counter failed!\n");
    
        FILE *record = fopen(records_bin, "r+b");
        if (record != 0)
        {
            size_t result2 = fread(employee, *pCounter * sizeof(PAYROLL), 1, record);
            if (result2 == 1)
                printf("Upload successful!\n");
            else
                fprintf(stderr, "Failed to read records!\n");
            fclose(record);
        }
        else
            fprintf(stderr, "Error opening file!");
    }
    
    int main(void)
    {
        PAYROLL emps[] =
        {
            { 1066, "William the Conqueror" },
            { 1819, "Victoria" },
            { 1689, "William and Mary" },
        };
    
        for (int i = 1; i <= 3; i++)
        {
            long emp_count = i;
            printf("Employee count = %ld\n", emp_count);
            backUp(emps, &emp_count);
            upload(emps, &emp_count);
            for (int j = 0; j < emp_count; j++)
                printf("%4ld: %s\n", emps[j].emp_id, emps[j].emp_name);
        }
    
        return 0;
    }
    

    Note that I've factored out the file names so that you only have to change a single line to change the files used. Sample output:

    $ Employee count = 1
    Counter: 1
    Upload successful!
    1066: William the Conqueror
    Employee count = 2
    Counter: 2
    Upload successful!
    1066: William the Conqueror
    1819: Victoria
    Employee count = 3
    Counter: 3
    Upload successful!
    1066: William the Conqueror
    1819: Victoria
    1689: William and Mary
    $ odx counter.bin
    0x0000: 03 00 00 00 00 00 00 00                           ........
    0x0008:
    $ odx records.bin
    0x0000: 2A 04 00 00 00 00 00 00 57 69 6C 6C 69 61 6D 20   *.......William 
    0x0010: 74 68 65 20 43 6F 6E 71 75 65 72 6F 72 00 00 00   the Conqueror...
    0x0020: 00 00 00 00 00 00 00 00 1B 07 00 00 00 00 00 00   ................
    0x0030: 56 69 63 74 6F 72 69 61 00 00 00 00 00 00 00 00   Victoria........
    0x0040: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   ................
    0x0050: 99 06 00 00 00 00 00 00 57 69 6C 6C 69 61 6D 20   ........William 
    0x0060: 61 6E 64 20 4D 61 72 79 00 00 00 00 00 00 00 00   and Mary........
    0x0070: 00 00 00 00 00 00 00 00                           ........
    0x0078:
    $
    

    (odx is just a hex dump program. Pick your own program that does an equivalent job — od -c is a fallback, though I don't particularly like its formatting.)