📁 File Handling in C

Until now, most of our C programs have worked with data stored temporarily while the program is running. File handling allows a program to store data in files so that the data can remain available after the program ends.

C provides file-handling facilities through the standard I/O header <stdio.h>.

Core idea:

A file is a persistent stream of data. In C, a program commonly works with a file through a FILE * stream and functions such as fopen(), fprintf(), fscanf(), fgets(), fputs(), fread(), fwrite(), and fclose().

15.1 What Is File Handling?

File handling means using a program to create, open, read, write, update, or close files.

For example, a student-management application may store:

  • Student ID
  • Student name
  • Marks
  • Attendance
  • Course information

If these values are kept only in normal variables, they disappear when the program terminates. Writing them to a file provides persistent storage.

15.2 Why Do We Need Files?

Temporary Data

Variables normally hold data while the program is executing.

Persistent Data

Files allow information to remain available after the program exits.

Large Data

Files can store much more information than can conveniently be kept in a small set of variables.

Data Exchange

Files can be used to exchange information between programs and processes.

15.3 File Streams in C

C's standard I/O model represents an open file through a stream.

The programmer normally uses a pointer of type:

FILE *file;

The type FILE is defined by <stdio.h>.

 Your C Program | v FILE * | v C Standard I/O | v Operating System | v File / Device 

The internal representation of FILE is implementation-defined. The program should use the standard library functions rather than depending on internal members of the FILE object.

15.4 The fopen() Function

The first major operation is opening a file.

FILE *fopen(const char *filename, const char *mode);

Example:

FILE *file; file = fopen("data.txt", "r");

If the operation succeeds, fopen() returns a stream pointer. If it fails, it returns NULL.

Always check the result of fopen().
FILE *file = fopen("data.txt", "r"); if (file == NULL) { printf("Could not open file\n"); }

15.5 File Opening Modes

Mode Purpose
"r" Open an existing file for reading.
"w" Open for writing; creates a new file or truncates an existing file.
"a" Open for writing at the end; creates the file if needed.
"r+" Open an existing file for reading and writing.
"w+" Open for reading and writing; creates or truncates the file.
"a+" Open for reading and writing with writes directed to the end.
Important difference:

Opening a file with "w" can destroy the previous contents by truncating the file. Use it carefully.

15.6 Text and Binary Modes

The standard library distinguishes text and binary stream modes.

Binary mode is selected by adding b:

"rb" "wb" "ab" "rb+" "wb+" "ab+"
Text Binary
"r" "rb"
"w" "wb"
"a" "ab"

Binary mode is useful when working with binary representations where text translation should not occur.

15.7 Reading a File

One simple character-at-a-time method uses fgetc().

#include <stdio.h> int main(void) { FILE *file; int ch; file = fopen("data.txt", "r"); if (file == NULL) { printf("Unable to open file\n"); return 1; } while ((ch = fgetc(file)) != EOF) { putchar(ch); } fclose(file); return 0; }
Why is ch an int?

Because fgetc() must be able to return every possible unsigned char value as well as the special value EOF.

15.8 EOF — End of File

EOF is a special negative integer value used by input functions to indicate an end-of-file or input error condition.

int ch; while ((ch = fgetc(file)) != EOF) { putchar(ch); }
Do not use char ch for this pattern.

A char may not be able to represent the distinct EOF value. Using int allows the program to distinguish character values from EOF.

15.9 Writing to a File with fputc()

fputc() writes one character to a stream.

#include <stdio.h> int main(void) { FILE *file; file = fopen("data.txt", "w"); if (file == NULL) { return 1; } fputc('H', file); fputc('i', file); fputc('\n', file); fclose(file); return 0; }

The file receives:

Hi

15.10 Writing Text with fprintf()

fprintf() works similarly to printf(), except that the destination stream is specified.

#include <stdio.h> int main(void) { FILE *file = fopen("student.txt", "w"); if (file == NULL) { return 1; } fprintf(file, "ID = %d\n", 101); fprintf(file, "Marks = %.2f\n", 87.5); fclose(file); return 0; }

The first argument identifies the destination stream.

15.11 Reading Formatted Data with fscanf()

fscanf() reads formatted input from a specified stream.

#include <stdio.h> int main(void) { FILE *file; int id; float marks; file = fopen("student.txt", "r"); if (file == NULL) { return 1; } if (fscanf(file, "%d %f", &id, &marks) == 2) { printf("ID = %d\n", id); printf("Marks = %.2f\n", marks); } fclose(file); return 0; }
Check the return value.

fscanf() returns the number of input items successfully assigned, or EOF if an input failure occurs before the first conversion.

15.12 Reading Lines with fgets()

For text files, fgets() is often convenient for reading one line at a time.

char line[100]; while (fgets(line, sizeof line, file) != NULL) { printf("%s", line); }

If a newline is read and there is enough room in the array, it is retained in the string.

15.13 Writing Lines with fputs()

fputs() writes a string to a stream.

fputs("CodeBhavya\n", file);
Important:

Unlike puts(), fputs() does not automatically add a newline. Add \n yourself when needed.

15.14 Closing a File with fclose()

After finishing file operations, close the stream.

fclose(file);

A successful fclose() returns zero. A nonzero return indicates an error.

Why close the file?
  • Releases resources associated with the stream.
  • Completes required output processing.
  • Allows the operating system/application to release the stream.

15.15 Complete Write and Read Program

#include <stdio.h> int main(void) { FILE *file; int number; file = fopen("number.txt", "w"); if (file == NULL) { printf("Unable to create file\n"); return 1; } fprintf(file, "%d\n", 250); fclose(file); file = fopen("number.txt", "r"); if (file == NULL) { printf("Unable to open file\n"); return 1; } if (fscanf(file, "%d", &number) == 1) { printf("Number = %d\n", number); } fclose(file); return 0; }

The program demonstrates the complete basic cycle:

 Open for writing | v Write 250 | v Close | v Open for reading | v Read 250 | v Close 

15.16 Append Mode

The "a" mode is used when new data should be written at the end of the existing file.

FILE *file = fopen("log.txt", "a");

If the file does not exist, it is created.

fprintf(file, "New log entry\n");

Existing contents are preserved.

15.17 Read and Write Modes

The + versions allow both reading and writing.

Mode Read? Write? Existing contents
r+ Yes Yes Must already exist
w+ Yes Yes Truncated if it exists
a+ Yes Yes Preserved; writes go to end

15.18 File Position

A stream maintains a current file position that determines where the next operation occurs.

 File: A B C D E F G H I J ^ | Current position 

Reading or writing generally advances the stream position according to the operation.

15.19 ftell()

ftell() reports the current file position indicator for a stream.

long position; position = ftell(file);

On success, it returns a nonnegative value representing the position in a form suitable for later positioning with the corresponding standard functions. On failure it returns -1L.

15.20 fseek()

fseek() changes the file position.

fseek(file, 0, SEEK_SET);

Common origins include:

Constant Meaning
SEEK_SET Beginning of the file.
SEEK_CUR Current position.
SEEK_END End of the file.

15.21 rewind()

rewind() moves the file position back to the beginning of the stream.

rewind(file);

It is useful when the same stream needs to be read again from the beginning.

15.22 Binary Files

Binary file operations work with blocks of bytes rather than formatted text.

The major functions are:

  • fread()
  • fwrite()

Example:

int numbers[3] = {10, 20, 30}; fwrite(numbers, sizeof numbers[0], 3, file);

And reading:

int numbers[3]; fread(numbers, sizeof numbers[0], 3, file);

15.23 fread()

The general form is:

size_t fread( void *ptr, size_t size, size_t count, FILE *stream );

It attempts to read up to count objects, each of size bytes, into the memory beginning at ptr.

int numbers[5]; size_t n = fread( numbers, sizeof numbers[0], 5, file );

The return value is the number of complete objects successfully read.

15.24 fwrite()

The general form is:

size_t fwrite( const void *ptr, size_t size, size_t count, FILE *stream );

Example:

int numbers[3] = {10, 20, 30}; size_t written = fwrite( numbers, sizeof numbers[0], 3, file );

The return value is the number of complete objects successfully written.

15.25 Structure Records and Binary Files

A structure can be written as a block of its object representation:

struct Student { int id; float marks; }; struct Student student = {101, 88.5f}; fwrite(&student, sizeof student, 1, file);

It can later be read into a structure object:

fread(&student, sizeof student, 1, file);
Important portability warning:

Writing raw structure representations to binary files can make files dependent on implementation details such as data representation, padding, alignment, byte order, and type sizes. Such files are not automatically portable across different systems or C implementations.

15.26 feof()

feof() tells whether the end-of-file indicator is set for a stream.

if (feof(file)) { printf("End-of-file indicator is set\n"); }
Very common interview trap:

Do not use while (!feof(file)) as the primary condition for reading data. EOF is normally detected after a read attempt fails to produce more input.

Prefer the result of the actual input function:

while (fgets(line, sizeof line, file) != NULL) { ... }

15.27 ferror()

ferror() checks whether the stream's error indicator is set.

if (ferror(file)) { printf("A file error occurred\n"); }

This helps distinguish an input termination condition from an actual I/O error in appropriate situations.

15.28 clearerr()

clearerr() clears the end-of-file and error indicators for a stream.

clearerr(file);

This is useful when a program intentionally wants to continue using a stream after handling a prior indicator condition.

15.29 perror() and File Errors

When an operation fails, perror() can print a message based on the current errno value.

#include <stdio.h> int main(void) { FILE *file = fopen("missing.txt", "r"); if (file == NULL) { perror("fopen"); return 1; } fclose(file); return 0; }

This is often more informative than printing only "file error".

15.30 Temporary Files

The standard library also provides facilities for temporary files.

For example:

FILE *file = tmpfile();

tmpfile() creates a temporary binary update stream and returns a stream pointer, or NULL on failure.

The exact lifetime and naming behavior are handled by the implementation according to the standard's requirements and the host environment.

15.31 Standard Streams

C starts with three standard text streams available through <stdio.h>:

Stream Typical purpose
stdin Standard input
stdout Standard output
stderr Standard error output

For example:

fprintf(stderr, "Something went wrong\n");

15.32 File Handling Program Trace

FILE *file; file = fopen("marks.txt", "w"); fprintf(file, "85\n"); fclose(file);
 Step 1 file | v No stream yet Step 2 fopen("marks.txt", "w") | v file | v Open stream | v marks.txt Step 3 fprintf(file, "85\n") | v File receives: 85 Step 4 fclose(file) | v Stream closed 

15.33 File Reading Trace

FILE *file = fopen("data.txt", "r"); char line[50]; while (fgets(line, sizeof line, file) != NULL) { printf("%s", line); } fclose(file);
 data.txt Line 1 Line 2 Line 3 | v fgets() | v line[50] | v printf() | v next fgets() | v NULL | v Loop ends | v fclose() 

15.34 Text File vs Binary File

Text File Binary File
Designed for character/text representation Works with bytes/object representations
Human-readable when contents are textual May not be directly human-readable
fprintf(), fscanf(), fgets(), fputs() fread(), fwrite()
Useful for logs and simple text data Useful for structured binary data where appropriate

15.35 Updating a File Safely

When a program needs to update stored information, it must carefully choose the opening mode and manage the file position.

For example:

FILE *file = fopen("data.txt", "r+");

The stream permits both reading and writing, but the programmer must follow the standard's rules for switching between reading and writing operations.

Important:

When using an update stream such as r+, w+, or a+, switching between input and output generally requires an appropriate positioning operation such as fseek(), fsetpos(), or rewind(), or an input operation that reaches end-of-file, according to the C standard's stream rules.

15.36 Common File Handling Mistakes

Mistake 1

Using a file pointer without checking whether fopen() returned NULL.

Mistake 2

Using "w" when the intention was to preserve existing data.

Mistake 3

Forgetting to close a stream.

Mistake 4

Using while (!feof(file)) as the main reading condition.

Mistake 5

Using char instead of int for fgetc() results when EOF must be distinguished.

Mistake 6

Assuming binary structure files are portable between all systems.

15.37 Common Confusions

Confusion Correct Understanding
fopen() creates every file Creation depends on the selected mode and whether the operation succeeds.
"w" appends data No. It writes from the beginning and truncates an existing file.
"a" overwrites the file No. It preserves existing contents and writes at the end.
EOF is a character stored in every file No. It is a special return value used by input functions.
feof() tells us the next read will fail Not exactly. It reports whether the stream's EOF indicator is already set.
fclose() deletes a file No. It closes the stream.
Binary file means encrypted file No. Binary describes representation, not security.

15.38 Complete File Handling Example

#include <stdio.h> int main(void) { FILE *file; int i; file = fopen("numbers.txt", "w"); if (file == NULL) { perror("numbers.txt"); return 1; } for (i = 1; i <= 5; i++) { fprintf(file, "%d\n", i * 10); } if (fclose(file) != 0) { perror("fclose"); return 1; } file = fopen("numbers.txt", "r"); if (file == NULL) { perror("numbers.txt"); return 1; } printf("Stored numbers:\n"); while (fscanf(file, "%d", &i) == 1) { printf("%d\n", i); } if (ferror(file)) { perror("numbers.txt"); fclose(file); return 1; } fclose(file); return 0; }
 PROGRAM | v fopen("numbers.txt", "w") | v Write 10, 20, 30, 40, 50 | v fclose() | v fopen("numbers.txt", "r") | v Read values | v Display values | v fclose() 

16.17 Quick Revision

📌 FILE * → File pointer

📌 fopen() → Opens a file

📌 fclose() → Closes a file

📌 fprintf() → Writes formatted data

📌 fscanf() → Reads formatted data

📌 fputc() → Writes one character

📌 fgetc() → Reads one character

📌 fputs() → Writes a string

📌 fgets() → Reads a line/string

📌 fread() → Reads binary data

📌 fwrite() → Writes binary data

📌 fseek() → Moves file position

📌 ftell() → Gets current position

📌 rewind() → Returns to beginning

📌 EOF → End-of-file condition
INTERACTIVE LEARNING

🎬 File Handling — File Lifecycle

Follow the normal sequence for safely opening, using, and closing a file.

PROGRAM TRACING

🔎 Program Tracing — File Handling

Trace writing to a file stream, moving back to the beginning, reading the value, and closing the stream.

16.18 Quick MCQs

Select an answer first, then click Check Answer. A correct choice becomes green. If the answer is wrong, your choice becomes red and the correct option becomes green. The explanation appears below.

1. Which type is used for a file pointer?
2. Which function opens a file?
3. Which function closes a file?
4. Which mode opens a file for reading?
5. Which mode can erase existing contents when opening a file?
6. Which mode is used to append data?
7. Which function writes formatted data to a file?
8. Which function reads one character from a file?
9. Which function writes binary blocks?
10. Which function changes the file position?
PRACTICE

16.19 🎯 Practice Problems

Practice text files, binary files, append mode, copying, searching, position functions, and record management. Use 💻 Solve It Yourself first, open Hint only when needed, and use Show Program after attempting the problem.

📈 File Handling Practice Progress
Solved 0 / 20
Completed with Solution 0
Total Score 0 / 2000
Completion 0%
A problem counts as Solved when all test cases pass without opening the full solution. Problems completed after viewing the official solution are tracked separately.
1. Create and Open a Text File for Writing

Problem 1: Create a text file named data.txt using write mode and report whether opening succeeded.

Input: No input.

Output: Print "File Created" if the file opens successfully.

2. Write Student Name and Marks

Problem 2: Write a student's one-word name and marks to a text file, then reopen the file and display the stored record.

Input: One-word name and integer marks.

Output: Print the record read back from the file.

3. Read and Display a Text File

Problem 3: Write an input line to a text file and then read and display the complete file contents.

Input: One line of text.

Output: Print the same line after reading it from the file.

4. Write Characters Using fputc()

Problem 4: Write a word to a file one character at a time using fputc(), then display the stored word.

Input: One word.

Output: Print the stored word.

5. Read Characters Using fgetc()

Problem 5: Store a line in a file and read it character by character using fgetc().

Input: One line of text.

Output: Print the text read by fgetc().

6. Write a String Using fputs()

Problem 6: Write a complete input line to a file using fputs(), then print the stored line.

Input: One line of text.

Output: Print the stored line.

7. Read Lines Using fgets()

Problem 7: Create a file containing three lines and read them back using fgets().

Input: Three lines of text.

Output: Print the three lines in the same order.

8. Count Characters in a File

Problem 8: Store a line in a text file and count the number of characters using file reading.

Input: One line of text.

Output: Print the number of stored characters.

9. Count Lines in a File

Problem 9: Store N input lines in a file and count how many lines are present.

Input: N followed by N lines.

Output: Print N as counted from the file.

10. Count Words in a Text File

Problem 10: Store a sentence in a file and count its whitespace-separated words.

Input: One line of text.

Output: Print the word count.

11. Append a New Record

Problem 11: Create a file with one record, append a second record using append mode, then display both records.

Input: Two lines, one record per line.

Output: Print the two stored records in order.

12. Copy One File to Another

Problem 12: Store input text in source.txt, copy it to destination.txt character by character, then display the destination file.

Input: One line of text.

Output: Print the copied text.

13. Store Student Details in a Binary File

Problem 13: Read one student record, write the structure to a binary file using fwrite(), then report success.

Input: Roll number, one-word name, and marks.

Output: Print "Binary Record Stored".

14. Read Student Details from a Binary File

Problem 14: Write one student structure to a binary file, then read it back with fread() and display it.

Input: Roll number, one-word name, and marks.

Output: Print the record read from the binary file.

15. Demonstrate fseek()

Problem 15: Write ABCDE to a file, use fseek() to move to offset 2 from the beginning, and print the character at that position.

Input: No input.

Output: Print "C".

16. Find Current File Position with ftell()

Problem 16: Write ABCDE, reopen the file, read two characters, and print the current file position using ftell().

Input: No input.

Output: Print the reported position after reading two characters.

17. Move to the Beginning with rewind()

Problem 17: Read two characters from a file, call rewind(), and print the first character again.

Input: No input.

Output: Print "A".

18. Search for a Word in a Text File

Problem 18: Store one sentence in a file and search for a target word.

Input: First line: sentence. Second line: one target word.

Output: Print "Found" or "Not Found".

19. Store and Display 10 Student Records

Problem 19: Read exactly ten student records, store them in a text file, then display all records.

Input: Ten lines: roll number, one-word name, integer marks.

Output: Print the ten records, one per line.

20. Student Record Management System

Problem 20: Implement add, display, search, and update operations on student records stored in a text file within one program run.

Input: Four initial records count N and records, then search roll, then update roll and new marks.

Output: Print the search result, then all updated records.

16.20 Key Takeaway

🎯 Remember:

FILE * → File pointer

fopen() → Open

fclose() → Close

fprintf() → Formatted write

fscanf() → Formatted read

fputc() → Write character

fgetc() → Read character

fputs() → Write string

fgets() → Read line

fwrite() → Binary write

fread() → Binary read

fseek() → Move position

ftell() → Current position

rewind() → Beginning
INTERVIEW PREPARATION

🎤 File Handling — Interview Questions

1. Why must fopen() normally be checked against NULL?
2. What is the difference between "w" and "a" mode?
3. Why is int commonly used to store the result of fgetc()?
4. What is the difference between text and binary file operations?
5. What does fseek() do?
6. What does ftell() return?
7. What is a common safe pattern for binary structure files?
8. Why should every successfully opened stream eventually be closed?
PLACEMENT TIPS

💡 File Handling — Placement Tips

  • Always check the return value of fopen() before reading from or writing to the stream.
  • Choose file mode carefully: "w" can truncate existing content, while "a" preserves it and writes at the end.
  • Store fgetc() results in an int so that EOF can be distinguished from valid character values.
  • Check return values from fread(), fwrite(), fscanf(), and other I/O functions when correctness matters.
  • For random-access questions, clearly track the file-position indicator before and after fseek(), ftell(), and rewind().
  • Raw binary structure files are convenient for exercises, but they are not automatically portable across different machines or structure layouts.
EXTRA PRACTICE

✍️ File Handling — Extra Practice Questions

  1. Merge the contents of two text files into a third file.
  2. Count uppercase letters, lowercase letters, digits, and spaces in a file.
  3. Replace every occurrence of a target word while copying one text file to another.
  4. Store employee records in a binary file and search by employee ID.
  5. Update one fixed-size binary record using fseek().
  6. Create a simple file-backed login system that stores usernames and hashed-password placeholders.
← Previous Topic: Preprocessor & Header Files Next Topic: Dynamic Memory Allocation →