Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I determine if a file is empty?

Tags:

c

file-io

How do I determine if a file is empty? The file is opened by a C program running on the Windows platform. I want to open a file in append mode, and, if empty, first print a header to it.

// Open CSV & write header
report_csv = fopen("SNR.csv", "a+");
if (!report_csv) {
    fprintf(stderr, "Unable to open CSV output file...");
    return -1;
}
if (!ftell(report_csv)) {
    fprintf(report_csv, "Column A;Column B;Column C\n");
}
// ... print data to file
fclose(report_csv);

I was expecting ftell to return the current file size if the file was not empty, which happens because the code above is looped.

However, ftell always returns 0 and the header is printed multiple times.

I know I could fopen it with r and use fseek/ftell/fclose and then fopen it again with a+, but I think it's possible to do this without opening and closing the file multiple times.

like image 314
Benoit Duffez Avatar asked Jun 13 '12 13:06

Benoit Duffez


2 Answers

Actually, when fopening a file in append mode, the file pointer is initially at the begining of the file. It moves to the end of it as soon as you write something or use fseek.

I just needed to add fseek(report_csv, 0, SEEK_END); before my if (!ftell(report_csv)).

Let's check this.
Code:

#include <stdio.h>

int main(int argc, char **argv) {
    FILE *test;
    size_t size;
    char buf[100];

    /* Truncate file */
    test = fopen("test", "w");
    if (!test) {
        fprintf(stderr, "Cannot open file `test`!\n");
        return 1;
    }

    /* Write something */
    fprintf(test, "Something. ");
    fclose(test);

    /* Open in append */
    test = fopen("test", "a+");
    if (!test) {
        fprintf(stderr, "Cannot open `test` in append mode!\n");
        return 1;
    }

    /* Try to get the file size */
    size = ftell(test);
    printf("File pointer is: %d\n", size);
    fseek(test, 0, SEEK_END);
    size = ftell(test);
    printf("After `fseek(test, 0, SEEK_END)`, the file pointer is: %d\n", size);

    /* Append */
    fprintf(test, "And that. ");
    fclose(test);

    /* Same without fseek */
    test = fopen("test", "a+");
    if (!test) {
        fprintf(stderr, "Cannot open `test` in append mode!\n");
        return 1;
    }
    fprintf(test, "Hello! ");
    size = ftell(test);
    printf("File size is now: %d\n", size);
    fclose(test);

    /* Try to read */
    test = fopen("test", "r");
    if (!test) {
        fprintf(stderr, "Unable to open `test` for reading!\n");
        return 1;
    }
    printf("File contents:\n\t");
    while (test && !feof(test)) {
        fgets(buf, sizeof(buf), test);
        printf("%s", buf);
    }

    /* Cleanup & exit */
    fclose(test);
    printf("\n\nExiting.\n");

    return 0;
}

Output:

File pointer is: 0
After `fseek(test, 0, SEEK_END)`, the file pointer is: 11
File size is now: 28
File contents:
        Something. And that. Hello!

Exiting.
like image 143
Benoit Duffez Avatar answered Oct 23 '22 20:10

Benoit Duffez


When opening a file with fopen with the a+ mode, all writing operations will be performed at the end of the file. You can reposition the internal pointer to anywhere in the file for reading, but writing operations will move it back to the end of file. The initial pointer position for reading is at the beginning of the file.

So you need to call an fseek(pFile, 0, SEEK_END) on your FILE pointer.

like image 42
Alexandru C. Avatar answered Oct 23 '22 20:10

Alexandru C.