C Program to Read Content of a File: Complete Guide
C Program to Read Content of a File: A Comprehensive Tutorial
Reading a file in C involves opening the file, retrieving its contents, and closing it after use. The C Standard Library provides several functions for reading files depending on the type and format of the data. Understanding file reading is essential for data processing, configuration management, and persistent storage.
This tutorial provides an in-depth exploration of reading files in C: fopen, fgetc, fgets, fscanf, fread, fclose, practical examples, common pitfalls, and best practices for robust file handling.
Conceptual Introduction & Fundamentals
What is File Reading?
File reading is the process of opening a file, retrieving its contents into memory, and closing the file when done. C provides a standard I/O library (<stdio.h>) with functions for reading text and binary files.
Why File Reading Matters
- Persistent data: Load saved data from disk.
- Configuration files: Read program settings.
- Data processing: Analyze logs, CSV files, and structured data.
- Binary data: Load images, audio, and custom binary formats.
- Interoperability: Exchange data between programs.
File Reading Functions Overview
| Function | Reads | Suitable For |
|---|---|---|
fgetc() | Single character | Character-by-character processing |
fgets() | Line/String | Reading text files line by line |
fscanf() | Formatted data | Structured text files |
fread() | Binary blocks | Binary files |
Steps to Read a File
- Open the file:
fopen(filename, mode) - Read the data: Use appropriate function
- Close the file:
fclose(pointer)
Syntax & Core Mechanics
Opening a File
Syntax:
c
FILE *fopen(const char *filename, const char *mode);
Common modes:
"r": Read (text)"rb": Read (binary)"w": Write (text)"a": Append (text)
Example:
c
FILE *fp = fopen("file.txt", "r"); if (fp == NULL) { fprintf(stderr, "Unable to open file\n"); return EXIT_FAILURE; } Method 1: fgetc() — Character by Character
Reads one character at a time. Returns EOF at end of file.
c
#include <stdio.h> #include <stdlib.h> int main(void) { FILE *fp = fopen("file.txt", "r"); int ch; if (fp == NULL) { fprintf(stderr, "Unable to open file.\n"); return EXIT_FAILURE; } while ((ch = fgetc(fp)) != EOF) { putchar(ch); } fclose(fp); return EXIT_SUCCESS; } Expected output (if file.txt contains “Hello, World!”):
text
Hello, World!
Important: Use int ch, not char ch, to correctly handle EOF.
Method 2: fgets() — Line by Line
Reads one line (up to size - 1 characters) into a buffer.
c
#include <stdio.h> #include <stdlib.h> int main(void) { FILE *fp = fopen("file.txt", "r"); char buffer[256]; if (fp == NULL) { fprintf(stderr, "Unable to open file.\n"); return EXIT_FAILURE; } while (fgets(buffer, sizeof(buffer), fp) != NULL) { printf("%s", buffer); } fclose(fp); return EXIT_SUCCESS; } Expected output (file.txt with multiple lines):
text
Line 1 Line 2 Line 3
Method 3: fscanf() — Formatted Input
Reads formatted data according to a format string.
c
#include <stdio.h> #include <stdlib.h> int main(void) { FILE *fp = fopen("data.txt", "r"); char name[50]; int age; if (fp == NULL) { fprintf(stderr, "Unable to open file.\n"); return EXIT_FAILURE; } while (fscanf(fp, "%49s %d", name, &age) == 2) { printf("Name: %s, Age: %d\n", name, age); } fclose(fp); return EXIT_SUCCESS; } Expected output (data.txt contains “Alice 25\nBob 30\n”):
text
Name: Alice, Age: 25 Name: Bob, Age: 30
Security note: Use width limits like %49s to prevent buffer overflow.
Method 4: fread() — Binary Data
Reads blocks of binary data.
c
#include <stdio.h> #include <stdlib.h> struct Student { int roll; char name[30]; float marks; }; int main(void) { FILE *fp = fopen("students.dat", "rb"); struct Student s; if (fp == NULL) { fprintf(stderr, "Unable to open file.\n"); return EXIT_FAILURE; } while (fread(&s, sizeof(struct Student), 1, fp) == 1) { printf("Roll: %d, Name: %s, Marks: %.2f\n", s.roll, s.name, s.marks); } fclose(fp); return EXIT_SUCCESS; } Expected output (depends on binary file contents):
text
Roll: 1, Name: Alice, Marks: 85.50 Roll: 2, Name: Bob, Marks: 92.00
Closing a File
Always close files after use.
c
fclose(fp);
Full Practical Code Example with Explanation
This program demonstrates all file reading methods in a comprehensive text and binary file reader.
Program: File Content Reader
c
/** * file_reader.c * Demonstrates reading files using fgetc, fgets, fscanf, and fread. * Includes error handling and multiple reading modes. */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <errno.h> #define MAX_LINE_LEN 256 #define MAX_NAME_LEN 50 /* Structure for binary data */ typedef struct { int id; char name[MAX_NAME_LEN]; double score; } Record; /* Function prototypes */ void readCharByChar(const char *filename); void readLineByLine(const char *filename); void readFormatted(const char *filename); void readBinary(const char *filename); void demonstrateAllMethods(const char *filename); void createSampleFile(const char *filename); void createBinaryFile(const char *filename); int main(void) { int choice; char buffer[MAX_LINE_LEN]; char filename[MAX_NAME_LEN] = "sample.txt"; printf("=== File Content Reader ===\n"); /* Create sample files for demonstration */ createSampleFile(filename); createBinaryFile("sample.dat"); while (1) { printf("\n--- Menu ---\n"); printf("1. Read Character by Character (fgetc)\n"); printf("2. Read Line by Line (fgets)\n"); printf("3. Read Formatted Data (fscanf)\n"); printf("4. Read Binary Data (fread)\n"); printf("5. Demonstrate All Methods\n"); printf("6. Exit\n"); printf("Enter choice: "); fflush(stdout); if (fgets(buffer, sizeof(buffer), stdin) == NULL) { fprintf(stderr, "Error reading choice.\n"); return EXIT_FAILURE; } choice = atoi(buffer); switch (choice) { case 1: readCharByChar(filename); break; case 2: readLineByLine(filename); break; case 3: readFormatted(filename); break; case 4: readBinary("sample.dat"); break; case 5: demonstrateAllMethods(filename); break; case 6: printf("Exiting.\n"); return EXIT_SUCCESS; default: printf("Invalid choice. Please try again.\n"); break; } } return EXIT_SUCCESS; } /* Reads file character by character using fgetc */ void readCharByChar(const char *filename) { printf("\n=== Reading with fgetc ===\n"); FILE *fp = fopen(filename, "r"); if (fp == NULL) { fprintf(stderr, "Error opening %s: %s\n", filename, strerror(errno)); return; } int ch; int charCount = 0; while ((ch = fgetc(fp)) != EOF) { putchar(ch); charCount++; } printf("\n(Total characters: %d)\n", charCount); if (ferror(fp)) { fprintf(stderr, "Error reading file.\n"); } fclose(fp); } /* Reads file line by line using fgets */ void readLineByLine(const char *filename) { printf("\n=== Reading with fgets ===\n"); FILE *fp = fopen(filename, "r"); if (fp == NULL) { fprintf(stderr, "Error opening %s: %s\n", filename, strerror(errno)); return; } char buffer[MAX_LINE_LEN]; int lineCount = 0; while (fgets(buffer, sizeof(buffer), fp) != NULL) { printf("Line %d: %s", ++lineCount, buffer); } printf("(Total lines: %d)\n", lineCount); if (ferror(fp)) { fprintf(stderr, "Error reading file.\n"); } fclose(fp); } /* Reads formatted data using fscanf */ void readFormatted(const char *filename) { printf("\n=== Reading with fscanf ===\n"); FILE *fp = fopen(filename, "r"); if (fp == NULL) { fprintf(stderr, "Error opening %s: %s\n", filename, strerror(errno)); return; } char name[MAX_NAME_LEN]; int age; float score; int recordCount = 0; while (fscanf(fp, "%49s %d %f", name, &age, &score) == 3) { printf("Record %d: Name=%s, Age=%d, Score=%.2f\n", ++recordCount, name, age, score); } printf("(Total records: %d)\n", recordCount); if (ferror(fp)) { fprintf(stderr, "Error reading file.\n"); } fclose(fp); } /* Reads binary data using fread */ void readBinary(const char *filename) { printf("\n=== Reading with fread (Binary) ===\n"); FILE *fp = fopen(filename, "rb"); if (fp == NULL) { fprintf(stderr, "Error opening %s: %s\n", filename, strerror(errno)); return; } Record record; int recordCount = 0; while (fread(&record, sizeof(Record), 1, fp) == 1) { printf("Record %d: ID=%d, Name=%s, Score=%.2f\n", ++recordCount, record.id, record.name, record.score); } printf("(Total records: %d)\n", recordCount); if (ferror(fp)) { fprintf(stderr, "Error reading file.\n"); } fclose(fp); } /* Demonstrates all reading methods */ void demonstrateAllMethods(const char *filename) { readCharByChar(filename); readLineByLine(filename); readFormatted(filename); readBinary("sample.dat"); } /* Creates a sample text file */ void createSampleFile(const char *filename) { FILE *fp = fopen(filename, "w"); if (fp == NULL) { fprintf(stderr, "Error creating %s\n", filename); return; } fprintf(fp, "Alice 25 85.5\n"); fprintf(fp, "Bob 30 92.0\n"); fprintf(fp, "Charlie 22 78.5\n"); fclose(fp); printf("Created sample text file: %s\n", filename); } /* Creates a sample binary file */ void createBinaryFile(const char *filename) { FILE *fp = fopen(filename, "wb"); if (fp == NULL) { fprintf(stderr, "Error creating %s\n", filename); return; } Record records[] = { {1, "Alice", 85.5}, {2, "Bob", 92.0}, {3, "Charlie", 78.5} }; for (int i = 0; i < 3; i++) { fwrite(&records[i], sizeof(Record), 1, fp); } fclose(fp); printf("Created sample binary file: %s\n", filename); } Explanation of File Reading Methods
fgetc: Reads one character at a time; counts characters.fgets: Reads line by line; counts lines.fscanf: Reads formatted records; counts records.fread: Reads binary structures; counts records.- Error handling: Checks
fopenreturn, usesstrerror, checksferror.
Expected Output (sample run)
text
=== File Content Reader === Created sample text file: sample.txt Created sample binary file: sample.dat --- Menu --- 1. Read Character by Character (fgetc) 2. Read Line by Line (fgets) 3. Read Formatted Data (fscanf) 4. Read Binary Data (fread) 5. Demonstrate All Methods 6. Exit Enter choice: 1 === Reading with fgetc === Alice 25 85.5 Bob 30 92.0 Charlie 22 78.5 (Total characters: 51) --- Menu --- ... Enter choice: 2 === Reading with fgets === Line 1: Alice 25 85.5 Line 2: Bob 30 92.0 Line 3: Charlie 22 78.5 (Total lines: 3) --- Menu --- ... Enter choice: 3 === Reading with fscanf === Record 1: Name=Alice, Age=25, Score=85.50 Record 2: Name=Bob, Age=30, Score=92.00 Record 3: Name=Charlie, Age=22, Score=78.50 (Total records: 3) --- Menu --- ... Enter choice: 4 === Reading with fread (Binary) === Record 1: ID=1, Name=Alice, Score=85.50 Record 2: ID=2, Name=Bob, Score=92.00 Record 3: ID=3, Name=Charlie, Score=78.50 (Total records: 3)
Common Pitfalls, Edge Cases & Memory Considerations
1. Not Checking fopen Return
Using a NULL file pointer causes crashes.
c
FILE *fp = fopen("missing.txt", "r"); fgetc(fp); // BUG: fp is NULL Solution: Always check if (fp != NULL) after opening.
2. Using char Instead of int for fgetc
char may not represent EOF correctly.
c
char ch; // BUG: should be int while ((ch = fgetc(fp)) != EOF) { ... } Solution: Use int ch; to correctly handle EOF (which is typically -1).
3. Forgetting to Close Files
Leaving files open wastes resources and may cause data loss.
c
FILE *fp = fopen("file.txt", "r"); /* ... reading ... */ /* Missing fclose(fp); */ Solution: Always fclose files after use.
4. Buffer Overflow with fscanf
Using %s without width limit can overflow the buffer.
c
char name[50]; fscanf(fp, "%s", name); // BUG: no width limit
Solution: Use %49s to limit input.
5. Assuming fgets Always Removes Newline
fgets includes the newline character if space allows.
c
fgets(buffer, sizeof(buffer), fp); /* buffer includes '\n' */
Solution: Remove newline if not needed: buffer[strcspn(buffer, "\n")] = '\0';
6. Not Checking ferror
Read errors may not be detected without checking ferror.
c
while (fgets(buffer, sizeof(buffer), fp) != NULL) { ... } /* Missing if (ferror(fp)) check */ Solution: Check ferror(fp) after the loop.
7. Reading Binary with Text Functions
Using text functions on binary files corrupts data.
c
fgets(buffer, sizeof(buffer), binaryFile); // BUG: binary file
Solution: Use fread for binary files with "rb" mode.
8. Assuming File Exists
Opening a non-existent file in read mode returns NULL.
Solution: Check fopen return and handle gracefully.
9. Not Handling EOF Correctly
EOF is not a character; it’s a special value indicating end of file.
c
while (!feof(fp)) { // Anti-pattern fgets(buffer, sizeof(buffer), fp); printf("%s", buffer); // May print last line twice } Solution: Use the return value of the read function:
c
while (fgets(buffer, sizeof(buffer), fp) != NULL) { printf("%s", buffer); } 10. Memory Considerations
- File reading functions use buffers; large buffers consume stack space.
freadreads directly into user-provided memory.- For very large files, read in chunks rather than all at once.
- Binary structures may have padding; ensure consistent structure layout.
Summary & Best Practices
Reading files in C involves opening with fopen, reading with appropriate functions (fgetc, fgets, fscanf, fread), and closing with fclose. Proper error handling is essential for robust file operations.
Key Takeaways
fgetc: Character by character.fgets: Line by line.fscanf: Formatted data.fread: Binary data.- Always check
fopenreturn. - Use
intforfgetcreturn value. - Always close files with
fclose. - Check
ferrorfor read errors.
Best Practices
- Always check
fopenreturn value before using the file pointer. - Use
intforfgetcto handleEOFcorrectly. - Use width limits in
fscanfto prevent buffer overflow. - Use the return value of read functions (not
feof) for loop control. - Always close files with
fcloseafter use. - Check
ferrorafter reading to detect errors. - Use the correct mode (
"r"for text,"rb"for binary). - Remove trailing newline from
fgetsif not needed. - Handle missing files gracefully with error messages.
- Read large files in chunks rather than all at once.
By mastering file reading in C, you’ll write robust programs that effectively process both text and binary data from files.



