CodeWithAbdessamad

File Operations

File Operations

📁

In this section, we dive deep into the practical art of handling files in C. Whether you’re reading data from a text file, writing logs, or processing binary data, understanding file operations is fundamental to building robust applications. Let’s break down the process step by step.

Opening Files

Before you can interact with a file, you must open it using the fopen function. This function returns a FILE * pointer that serves as the handle for all subsequent file operations. The fopen function takes two arguments: the filename and the mode string.

Here’s a quick reference table for the common file modes:

Mode Description
r Open for reading (file must exist)
w Open for writing (truncates file if exists)
a Open for appending (file is created if doesn’t exist)
r+ Open for reading and writing (file must exist)
w+ Open for writing and reading (truncates file if exists)
a+ Open for appending and reading (file is created if doesn’t exist)

Pro Tip: Always check the return value of fopen to ensure the file was opened successfully. If fopen returns NULL, the file could not be opened.

Let’s look at a concrete example of opening a file for reading:

<code class="language-c">#include <stdio.h>

<p>int main() {</p>
<p>    FILE *fp = fopen("notes.txt", "r");</p>
<p>    if (fp == NULL) {</p>
<p>        printf("Error opening file.\n");</p>
<p>        return 1;</p>
<p>    }</p>
<p>    // ... proceed with file operations</p>
<p>    fclose(fp);</p>
<p>    return 0;</p>
<p>}</code>

Notice the check for NULL after fopen? This is critical to prevent crashes and unexpected behavior.

Reading Files

Once a file is open, you can read from it using various functions. The choice of function depends on your needs: do you want to read one character at a time, a line at a time, or formatted data?

Reading Character by Character

The fgetc function reads a single character from the file:

<code class="language-c">int ch = fgetc(fp);</code>

Here’s a simple example that reads and prints each character until the end of file (EOF):

<code class="language-c">#include <stdio.h>

<p>int main() {</p>
<p>    FILE *fp = fopen("notes.txt", "r");</p>
<p>    if (fp == NULL) {</p>
<p>        printf("Error opening file.\n");</p>
<p>        return 1;</p>
<p>    }</p>

<p>    int ch;</p>
<p>    while ((ch = fgetc(fp)) != EOF) {</p>
<p>        putchar(ch);</p>
<p>    }</p>

<p>    fclose(fp);</p>
<p>    return 0;</p>
<p>}</code>

Reading Lines

For more practical use, fgets reads a line (including the newline character) into a buffer:

<code class="language-c">char line[100];
<p>fgets(line, sizeof(line), fp);</code>

This is often used when you want to process text files line by line. Here’s an example that prints each line:

<code class="language-c">#include <stdio.h>
<p>#include <string.h></p>

<p>int main() {</p>
<p>    FILE *fp = fopen("notes.txt", "r");</p>
<p>    if (fp == NULL) {</p>
<p>        printf("Error opening file.\n");</p>
<p>        return 1;</p>
<p>    }</p>

<p>    char line[100];</p>
<p>    while (fgets(line, sizeof(line), fp) != NULL) {</p>
<p>        printf("Line: %s\n", line);</p>
<p>    }</p>

<p>    fclose(fp);</p>
<p>    return 0;</p>
<p>}</code>

Important: The fgets function is safer than fscanf for text files because it doesn’t cause buffer overflows (as long as you check the buffer size).

Writing Files

Writing to a file is the reverse of reading. You choose a function based on your needs: writing a single character, a string, formatted data, or binary data.

Writing Strings

The fputs function writes a string to a file:

<code class="language-c">fputs("Hello, world!", fp);</code>

Here’s a complete example that writes a line to a file:

<code class="language-c">#include <stdio.h>

<p>int main() {</p>
<p>    FILE *fp = fopen("output.txt", "w");</p>
<p>    if (fp == NULL) {</p>
<p>        printf("Error opening file.\n");</p>
<p>        return 1;</p>
<p>    }</p>

<p>    fputs("Hello, C Programming!\n", fp);</p>
<p>    fclose(fp);</p>
<p>    return 0;</p>
<p>}</code>

Writing Formatted Data

For more complex data, use fprintf to write formatted strings:

<code class="language-c">fprintf(fp, "Number: %d\n", 42);</code>

This is useful when you want to write data in a specific format. Here’s a full example:

<code class="language-c">#include <stdio.h>

<p>int main() {</p>
<p>    FILE *fp = fopen("data.txt", "w");</p>
<p>    if (fp == NULL) {</p>
<p>        printf("Error opening file.\n");</p>
<p>        return 1;</p>
<p>    }</p>

<p>    fprintf(fp, "Integer: 42\n");</p>
<p>    fprintf(fp, "Float: 3.14\n");</p>
<p>    fclose(fp);</p>
<p>    return 0;</p>
<p>}</code>

Closing Files

After you’re done with a file, it’s essential to close it using fclose. This function flushes any buffered data to the file and releases the file handle.

Why close? If you don’t close a file, your program might run out of file descriptors, or data might be lost if the file is not flushed.

Here’s a simple example that shows the importance of closing:

<code class="language-c">#include <stdio.h>

<p>int main() {</p>
<p>    FILE *fp = fopen("temp.txt", "w");</p>
<p>    if (fp == NULL) {</p>
<p>        printf("Error opening file.\n");</p>
<p>        return 1;</p>
<p>    }</p>

<p>    fprintf(fp, "This file was written but not closed.\n");</p>
<p>    // If we don't close, the file might not be written properly on some systems.</p>

<p>    // Close the file to ensure data is written</p>
<p>    fclose(fp);</p>

<p>    return 0;</p>
<p>}</code>

Critical Note: Always close the file after you’re done. Forgetting to close a file is a common mistake that can lead to data loss or resource leaks.

Summary

In this section, we’ve covered the essential file operations in C: opening, reading, writing, and closing files. Remember to always check the return value of fopen and always close the file with fclose to ensure data integrity and resource management. 📁✅

By mastering these operations, you’ll be able to handle files with confidence and build applications that work reliably across different environments.