shardul
shardul

Reputation: 129

How do I check if file was written to successfully?

I have written the function, don't know it that's correct but how do I return true and false using if condition?

Function bool save_book(Book, char)** Input Parameters: A pointer to a Book and a string representing a file name. Return Value: Return true if the book's contents were stored to a file successfully. Otherwise false. Note This function should create or open a file based on the file name and store each Line of the book in it.

Below is my code

bool save_book(Book *b, char* fileName){

FILE  *filePointer = fopen(fileName,"w");
for (int i = 0; i < pBook->lineCount; i++)
{
    fprintf(filePointer, "%s", b->lines[i]);
}
fclose(filePointer);

return true;
}

this is the struct I am using:

typedef struct _Book
{
   int characterCount;
   int lineCount;
   int maxLineCount;
   char **lines;
}Book;
 

Upvotes: 1

Views: 2517

Answers (1)

Schwern
Schwern

Reputation: 165546

You have to check every individual I/O operation.

To make it fun, they all return different things on error. fopen will return NULL. fprintf will return a negative number. fclose will return EOF.

Here it is annotated with a short list of what might go wrong at each step.

bool save_book(Book *b, char* fileName) {
    // Maybe the directory doesn't exist.
    // Maybe you don't have permission.
    // Maybe there's a disallowed character.
    // Maybe the disk is full.
    // Maybe it's a network drive and there's a network error.
    // Maybe the drive got unmounted.
    FILE  *filePointer = fopen(fileName,"w");
    if( filePointer == NULL ) {
        return false;
    }

    for (int i = 0; i < b->lineCount; i++)
    {
        // Maybe the disk is full.
        // Maybe it's a network drive and there's a network error.
        // Maybe the drive got unmounted.
        if( fprintf(filePointer, "%s", b->lines[i]) < 0 ) {
            // Even though the filePointer variable will be automatically freed
            // the underlying file handle will not be automatically closed.
            // There's a limit to how many open file handles one can have open.
            // No need to check for error, we know something has already gone wrong.
            fclose(filePointer);
            return false;
        }
    }
    // Maybe the disk is full.
    // Maybe it's a network drive and there's a network error.
    // Maybe the drive got unmounted.
    if( fclose(filePointer) != 0 ) {
        return false;
    }

    return true;
}

In reality you probably don't need to check fprintf, checking fclose should catch the same errors. But if you're writing a very large and expensive file you might want to know if you ran out of disk space sooner rather than later.

You can also optionally print the error. Each of those functions will set the global errno on failure. You can turn this into a human readable string with strerror.

    if( filePointer == NULL ) {
        fprintf(stderr, "Error while opening '%s' for writing: %s", fileName, strerror(errno));
        return false;
    }

Note that rather than checking for an exact error code, I tend to check for that which is not the success code. Rather than if( fclose(filePointer) == EOF ) I've checked for if( fclose(filePointer) != 0 ), the lack of a success code. This is a defense programming practice just in case the error is severe enough that it can't even return its correct error code (extremely unlikely in standard library code) or I didn't read the spec quite right.

Upvotes: 2

Related Questions