Tutorials Logic, IN info@tutorialslogic.com

C File Handling fopen, fread, fwrite, fclose: Tutorial, Examples, FAQs & Interview Tips

C File Handling fopen, fread, fwrite, fclose

C in C is best learned by connecting the rule to a small command-line program. Start with the smallest function, observe the output, and then add one realistic constraint so the concept becomes practical.

The key habit for this lesson is to watch pointer, array, or file buffer as it changes. That makes the topic easier to debug, easier to explain in interviews, and easier to use in real code without memorizing isolated syntax.

File I/O in C

C provides file I/O through the <stdio.h> library. Files are accessed through a FILE pointer. Always close files after use with fclose().

File Modes

Mode Description File Exists File Missing
"r" Read text Opens for reading Returns NULL
"w" Write text Truncates to empty Creates new file
"a" Append text Appends to end Creates new file
"r+" Read + Write Opens for both Returns NULL
"w+" Write + Read Truncates to empty Creates new file
"a+" Append + Read Appends, reads from start Creates new file
"rb" Read binary Opens for binary read Returns NULL
"wb" Write binary Truncates Creates new file

Key File Functions

Function Description
fopen(path, mode) Opens a file; returns FILE* or NULL on failure
fclose(fp) Closes the file and flushes buffer
fprintf(fp, fmt, ...) Writes formatted text to file
fscanf(fp, fmt, ...) Reads formatted data from file
fputc(c, fp) Writes a single character
fgetc(fp) Reads a single character
fputs(str, fp) Writes a string (no newline added)
fgets(buf, n, fp) Reads a line (up to n-1 chars)
fwrite(ptr, size, n, fp) Writes n binary blocks of given size
fread(ptr, size, n, fp) Reads n binary blocks of given size
fseek(fp, offset, origin) Moves file position pointer
ftell(fp) Returns current file position
rewind(fp) Resets position to beginning
feof(fp) Returns non-zero if end of file reached
ferror(fp) Returns non-zero if an error occurred

Write to File with fprintf, Read with fscanf

Write to File with fprintf, Read with fscanf
#include <stdio.h>

int main() {
    FILE *fp;

    // --- Write to file ---
    fp = fopen("students.txt", "w");
    if (fp == NULL) {
        printf("Error opening file!\n");
        return 1;
    }
    fprintf(fp, "Alice 20 3.85\n");
    fprintf(fp, "Bob   22 3.20\n");
    fprintf(fp, "Carol 21 3.65\n");
    fclose(fp);
    printf("Data written to students.txt\n");

    // --- Read from file ---
    fp = fopen("students.txt", "r");
    if (fp == NULL) {
        printf("Error opening file!\n");
        return 1;
    }

    char name[50];
    int  age;
    float gpa;

    printf("\nReading from file:\n");
    while (fscanf(fp, "%s %d %f", name, &age, &gpa) == 3) {
        printf("Name: %-10s Age: %d  GPA: %.2f\n", name, age, gpa);
    }
    fclose(fp);

    return 0;
}

Copy File Using fgetc / fputc

Copy File Using fgetc / fputc
#include <stdio.h>

int main() {
    FILE *src, *dest;
    int ch;

    src = fopen("students.txt", "r");
    if (src == NULL) { printf("Cannot open source file\n"); return 1; }

    dest = fopen("students_copy.txt", "w");
    if (dest == NULL) { fclose(src); printf("Cannot create dest file\n"); return 1; }

    // Copy character by character
    while ((ch = fgetc(src)) != EOF) {
        fputc(ch, dest);
    }

    fclose(src);
    fclose(dest);
    printf("File copied successfully!\n");

    // Read back using fgets
    dest = fopen("students_copy.txt", "r");
    char line[100];
    printf("\nContents of copy:\n");
    while (fgets(line, sizeof(line), dest) != NULL) {
        printf("%s", line);
    }
    fclose(dest);

    return 0;
}

Binary File I/O with fwrite / fread

Binary File I/O with fwrite / fread
#include <stdio.h>
#include <string.h>

typedef struct {
    char  name[30];
    int   age;
    float salary;
} Employee;

int main() {
    Employee emp[3] = {
        {"Alice", 30, 75000.0f},
        {"Bob",   25, 60000.0f},
        {"Carol", 35, 90000.0f}
    };

    // Write binary data
    FILE *fp = fopen("employees.bin", "wb");
    if (!fp) { printf("Cannot open file\n"); return 1; }
    fwrite(emp, sizeof(Employee), 3, fp);
    fclose(fp);
    printf("Binary data written.\n");

    // Read binary data
    Employee read_emp[3];
    fp = fopen("employees.bin", "rb");
    if (!fp) { printf("Cannot open file\n"); return 1; }
    int count = fread(read_emp, sizeof(Employee), 3, fp);
    fclose(fp);

    printf("\nRead %d records:\n", count);
    for (int i = 0; i < count; i++) {
        printf("%-10s Age: %d  Salary: %.2f\n",
               read_emp[i].name, read_emp[i].age, read_emp[i].salary);
    }

    // fseek and ftell
    fp = fopen("employees.bin", "rb");
    fseek(fp, sizeof(Employee), SEEK_SET);  // skip first record
    Employee second;
    fread(&second, sizeof(Employee), 1, fp);
    printf("\nSecond record: %s\n", second.name);
    printf("File position: %ld bytes\n", ftell(fp));
    fclose(fp);

    return 0;
}

Applied guide for C

Use C when the program needs a clear answer to a specific problem, not because the keyword looks familiar. In a real C task, first name the input, then name the transformation, then name the output. This small discipline shows whether the topic is being used correctly or only copied from an example.

A reliable practice flow is: create the smallest working function, add one normal case, add one edge case such as missing files and partial writes, and then confirm the result with compiler warnings and printed output. If the result surprises you, reduce the code until the behavior is visible again.

The most common trap here is ignoring failed opens, paths, and resource cleanup. Avoid it by writing one sentence before the code that explains why C is the right choice. After the code runs, verify the lesson by doing this: check the return value before reading or writing.

  • Identify the exact problem solved by C.
  • Trace pointer, array, or file buffer before and after the main operation.
  • Keep one intentionally broken version and explain the fix.
  • Connect the example to a small command-line program so the idea feels concrete.
Key Takeaways
  • I can explain where C fits inside a small command-line program.
  • I can point to the exact pointer, array, or file buffer affected by this topic.
  • I tested a normal case and an edge case involving missing files and partial writes.
  • I verified the result with compiler warnings and printed output instead of assuming it worked.
  • I can describe the main mistake: ignoring failed opens, paths, and resource cleanup.
Common Mistakes to Avoid
WRONG Ignoring failed opens, paths, and resource cleanup.
RIGHT Write the expected behavior first, then make the example prove it.
A one-line expectation turns the code from copied syntax into a testable idea.
WRONG Practicing only the perfect input.
RIGHT Also test missing files and partial writes before considering the lesson complete.
The edge case is where most interview follow-up questions begin.
WRONG Looking only at the final output.
RIGHT Trace pointer, array, or file buffer through each important step.
Tracing makes debugging faster because you can see the first incorrect state.

Practice Tasks

  • Build one small function that demonstrates C in a small command-line program.
  • Change the example to include missing files and partial writes and record the difference.
  • Break the example by deliberately ignoring failed opens, paths, and resource cleanup, then write the corrected version.
  • Explain the finished example in five bullet points: input, operation, output, failure case, and verification.

Frequently Asked Questions

Use it when the problem matches the behavior shown in the example and when the result can be verified through compiler warnings and printed output.

Start with a tiny case, then test missing files and partial writes. The main warning sign is ignoring failed opens, paths, and resource cleanup.

Trace pointer, array, or file buffer, predict the result, run the example, and compare your prediction with the actual output.

Ready to Level Up Your Skills?

Explore 500+ free tutorials across 20+ languages and frameworks.