Chapter 13: File Management in C
- LO 13.1: Define and open files using fopen()
- LO 13.2: Perform input/output operations on files
- LO 13.3: Handle errors during file operations
- LO 13.4: Implement random access to files
- LO 13.5: Use command line arguments in programs
13.1 Introduction to File Management
Until now, we have been using console-oriented I/O functions (scanf, printf) which use the terminal as the target. However, real-life problems involve large volumes of data that need to be stored permanently on disks. File operations in C allow us to:
- Store data permanently on disk
- Read data from files when needed
- Process large volumes of data efficiently
- Share data between different programs
Basic file operations include:
- Naming a file
- Opening a file
- Reading data from a file
- Writing data to a file
- Closing a file
13.2 File Pointers and the FILE Structure
All file operations in C use a special data type called FILE, defined in stdio.h. A file pointer is used to refer to an opened file.
FILE *fp; // Declare a file pointer
13.3 Opening a File: fopen()
The fopen() function is used to open a file. It returns a file pointer that is used for subsequent file operations.
FILE *fopen(const char *filename, const char *mode);
File opening modes:
| Mode | Description |
|---|---|
"r" |
Open for reading. File must exist. |
"w" |
Open for writing. Creates new file or truncates existing file. |
"a" |
Open for appending. Creates new file if it doesn't exist. |
"r+" |
Open for reading and writing. File must exist. |
"w+" |
Open for reading and writing. Creates new file or truncates existing. |
"a+" |
Open for reading and appending. Creates new file if it doesn't exist. |
"rb", "wb", "ab" |
Binary modes (similar to text modes but for binary files) |
📝 Worked-Out Problem 13.1
Opening a file for writing:
#include <stdio.h>
#include <stdlib.h>
int main() {
FILE *fp;
fp = fopen("test.txt", "w");
if (fp == NULL) {
printf("Error opening file!\n");
exit(1);
}
printf("File opened successfully!\n");
fprintf(fp, "Hello, World!\n");
fclose(fp);
return 0;
}
File opened successfully!
(Creates test.txt with content "Hello, World!")
13.4 Closing a File: fclose()
Always close a file after completing operations. This flushes buffers and breaks the link to the file.
int fclose(FILE *stream); // Returns 0 on success, EOF on error
13.5 Character I/O: getc() and putc()
These functions read and write a single character at a time.
int getc(FILE *stream); // Returns character or EOF int putc(int ch, FILE *stream);
📝 Worked-Out Problem 13.2
Character-oriented file operations:
#include <stdio.h>
#include <stdlib.h>
int main() {
FILE *f1, *f2;
char ch;
f1 = fopen("input.txt", "w");
if (f1 == NULL) {
printf("Cannot create file\n");
exit(1);
}
printf("Enter text (Ctrl+Z to end):\n");
while ((ch = getchar()) != EOF)
putc(ch, f1);
fclose(f1);
f1 = fopen("input.txt", "r");
f2 = fopen("output.txt", "w");
if (f1 == NULL || f2 == NULL) {
printf("File error\n");
exit(1);
}
while ((ch = getc(f1)) != EOF)
putc(ch, f2);
printf("File copied successfully!\n");
fclose(f1);
fclose(f2);
return 0;
}
13.6 String I/O: fgets() and fputs()
These functions read and write strings line by line.
char *fgets(char *str, int n, FILE *stream); // Reads at most n-1 characters int fputs(const char *str, FILE *stream);
📝 Worked-Out Problem 13.3
Reading and writing strings to files:
#include <stdio.h>
#include <stdlib.h>
int main() {
FILE *fp;
char str[100];
fp = fopen("data.txt", "w");
if (fp == NULL) {
printf("Cannot open file\n");
exit(1);
}
printf("Enter lines of text (empty line to stop):\n");
while (1) {
fgets(str, 100, stdin);
if (str[0] == '\n')
break;
fputs(str, fp);
}
fclose(fp);
fp = fopen("data.txt", "r");
printf("\nFile contents:\n");
while (fgets(str, 100, fp) != NULL)
printf("%s", str);
fclose(fp);
return 0;
}
13.7 Formatted I/O: fprintf() and fscanf()
These functions work like printf() and scanf() but operate on files.
int fprintf(FILE *stream, const char *format, ...); int fscanf(FILE *stream, const char *format, ...);
📝 Worked-Out Problem 13.4
Writing and reading mixed data types:
#include <stdio.h>
#include <stdlib.h>
struct student {
int roll;
char name[30];
float marks;
};
int main() {
FILE *fp;
struct student s1 = {101, "John", 85.5};
struct student s2;
fp = fopen("student.dat", "w");
if (fp == NULL) {
printf("Cannot open file\n");
exit(1);
}
fprintf(fp, "%d %s %.2f\n", s1.roll, s1.name, s1.marks);
fclose(fp);
fp = fopen("student.dat", "r");
fscanf(fp, "%d %s %f", &s2.roll, s2.name, &s2.marks);
printf("Read from file:\n");
printf("Roll: %d\n", s2.roll);
printf("Name: %s\n", s2.name);
printf("Marks: %.2f\n", s2.marks);
fclose(fp);
return 0;
}
Read from file:
Roll: 101
Name: John
Marks: 85.50
13.8 Integer I/O: getw() and putw()
These functions read and write integers to files. Note: These are not standard ANSI functions but are available in many compilers.
📝 Worked-Out Problem 13.5
Reading and writing integers using getw/putw:
#include <stdio.h>
#include <stdlib.h>
int main() {
FILE *f1, *f2, *f3;
int number, i;
f1 = fopen("DATA", "w");
printf("Enter numbers (-1 to stop):\n");
scanf("%d", &number);
while (number != -1) {
putw(number, f1);
scanf("%d", &number);
}
fclose(f1);
f1 = fopen("DATA", "r");
f2 = fopen("ODD", "w");
f3 = fopen("EVEN", "w");
while ((number = getw(f1)) != EOF) {
if (number % 2 == 0)
putw(number, f3);
else
putw(number, f2);
}
fclose(f1);
fclose(f2);
fclose(f3);
printf("\nODD numbers:\n");
f2 = fopen("ODD", "r");
while ((number = getw(f2)) != EOF)
printf("%d ", number);
printf("\nEVEN numbers:\n");
f3 = fopen("EVEN", "r");
while ((number = getw(f3)) != EOF)
printf("%d ", number);
printf("\n");
fclose(f2);
fclose(f3);
return 0;
}
Enter numbers (-1 to stop):
10 15 22 37 44 51 -1
ODD numbers:
15 37 51
EVEN numbers:
10 22 44
13.9 Error Handling: feof() and ferror()
These functions help detect errors during file operations and end-of-file conditions.
int feof(FILE *stream); // Returns non-zero if end of file reached int ferror(FILE *stream); // Returns non-zero if error occurred
📝 Worked-Out Problem 13.6
Error handling in file operations:
#include <stdio.h>
#include <stdlib.h>
int main() {
FILE *fp;
char filename[50];
char ch;
printf("Enter filename: ");
scanf("%s", filename);
fp = fopen(filename, "r");
if (fp == NULL) {
printf("Cannot open file %s\n", filename);
exit(1);
}
while (!feof(fp)) {
ch = fgetc(fp);
if (ferror(fp)) {
printf("Error reading from file\n");
break;
}
if (!feof(fp))
putchar(ch);
}
fclose(fp);
return 0;
}
13.10 Random Access to Files
Random access allows moving to any position in a file, not just sequential reading.
ftell() - Get current file position
long ftell(FILE *stream); // Returns current file position
rewind() - Reset to beginning
void rewind(FILE *stream); // Sets file position to beginning
fseek() - Move to specific position
int fseek(FILE *stream, long offset, int whence);
Whence values:
SEEK_SET(0) - Beginning of fileSEEK_CUR(1) - Current positionSEEK_END(2) - End of file
| Operation | Code |
|---|---|
| Skip n bytes forward | fseek(fp, n, SEEK_CUR); |
| Go to beginning | fseek(fp, 0, SEEK_SET); |
| Go to end | fseek(fp, 0, SEEK_END); |
| Go to nth byte from start | fseek(fp, n, SEEK_SET); |
| Go back n bytes | fseek(fp, -n, SEEK_CUR); |
| Go to nth byte from end | fseek(fp, -n, SEEK_END); |
📝 Worked-Out Problem 13.7
Random access using fseek and ftell:
#include <stdio.h>
#include <stdlib.h>
int main() {
FILE *fp;
char ch;
long position;
fp = fopen("sample.txt", "w+");
fprintf(fp, "This is a sample file for random access demonstration.");
rewind(fp); // Go to beginning
printf("File created. Size: %ld bytes\n\n", ftell(fp));
// Read and display every 5th character
printf("Every 5th character:\n");
for (position = 4; ; position += 5) {
fseek(fp, position, SEEK_SET);
if (feof(fp)) break;
ch = fgetc(fp);
if (!feof(fp))
printf("Position %ld: %c\n", position, ch);
}
// Read from the end
printf("\nReading from the end:\n");
fseek(fp, -2, SEEK_END);
position = ftell(fp);
printf("Second last character at position %ld: %c\n",
position, fgetc(fp));
fclose(fp);
return 0;
}
📝 Worked-Out Problem 13.8
Appending items to an existing file:
#include <stdio.h>
#include <stdlib.h>
struct item {
char name[20];
int quantity;
float price;
};
int main() {
FILE *fp;
struct item it;
char filename[50];
long n;
char ch;
printf("Enter filename: ");
scanf("%s", filename);
fp = fopen(filename, "a+");
if (fp == NULL) {
printf("Cannot open file\n");
exit(1);
}
do {
printf("\nEnter item name: ");
scanf("%s", it.name);
printf("Enter quantity: ");
scanf("%d", &it.quantity);
printf("Enter price: ");
scanf("%f", &it.price);
fprintf(fp, "%s %d %.2f\n", it.name, it.quantity, it.price);
printf("Add another item? (y/n): ");
scanf(" %c", &ch);
} while (ch == 'y' || ch == 'Y');
n = ftell(fp); // Save current position
fclose(fp);
// Display file contents
fp = fopen(filename, "r");
printf("\nFile contents:\n");
while (fscanf(fp, "%s %d %f", it.name, &it.quantity, &it.price) == 3) {
printf("%s\t%d\t%.2f\n", it.name, it.quantity, it.price);
}
fclose(fp);
return 0;
}
13.11 Command Line Arguments
Command line arguments allow passing parameters to a program when it is executed. The main() function can take two arguments:
int main(int argc, char *argv[])
argc(argument count) - number of command line argumentsargv(argument vector) - array of strings containing the argumentsargv[0]is always the program name
📝 Worked-Out Problem 13.9
Displaying command line arguments:
#include <stdio.h>
int main(int argc, char *argv[]) {
int i;
printf("Program name: %s\n", argv[0]);
printf("Number of arguments: %d\n", argc);
if (argc > 1) {
printf("Arguments:\n");
for (i = 1; i < argc; i++)
printf("argv[%d] = %s\n", i, argv[i]);
} else {
printf("No arguments provided.\n");
}
return 0;
}
gcc program.c -o program
./program hello world 123
Output:
Program name: ./program
Number of arguments: 4
Arguments:
argv[1] = hello
argv[2] = world
argv[3] = 123
📝 Worked-Out Problem 13.10
File copy program using command line arguments:
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[]) {
FILE *source, *target;
char ch;
if (argc != 3) {
printf("Usage: %s source_file target_file\n", argv[0]);
exit(1);
}
source = fopen(argv[1], "r");
if (source == NULL) {
printf("Cannot open source file %s\n", argv[1]);
exit(1);
}
target = fopen(argv[2], "w");
if (target == NULL) {
printf("Cannot create target file %s\n", argv[2]);
fclose(source);
exit(1);
}
while ((ch = fgetc(source)) != EOF)
fputc(ch, target);
printf("File copied successfully!\n");
fclose(source);
fclose(target);
return 0;
}
📝 Worked-Out Problem 13.11
Program to reverse characters in a file:
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[]) {
FILE *fp;
long i;
char ch;
if (argc != 2) {
printf("Usage: %s filename\n", argv[0]);
exit(1);
}
fp = fopen(argv[1], "r+");
if (fp == NULL) {
printf("Cannot open file %s\n", argv[1]);
exit(1);
}
fseek(fp, 0, SEEK_END);
long size = ftell(fp);
printf("Reversing %ld characters in %s...\n", size, argv[1]);
for (i = 0; i < size/2; i++) {
char ch1, ch2;
// Read character from beginning
fseek(fp, i, SEEK_SET);
ch1 = fgetc(fp);
// Read character from end
fseek(fp, size - 1 - i, SEEK_SET);
ch2 = fgetc(fp);
// Swap them
fseek(fp, i, SEEK_SET);
fputc(ch2, fp);
fseek(fp, size - 1 - i, SEEK_SET);
fputc(ch1, fp);
}
printf("File reversed successfully.\n");
fclose(fp);
return 0;
}
13.12 Binary File Operations
For binary files, we use fread() and fwrite() functions.
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream); size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);
📝 Worked-Out Problem 13.12
Writing and reading structures to binary file:
#include <stdio.h>
#include <stdlib.h>
struct record {
int id;
char name[30];
float salary;
};
int main() {
FILE *fp;
struct record emp1 = {101, "John Doe", 45000.50};
struct record emp2;
fp = fopen("employee.dat", "wb");
if (fp == NULL) {
printf("Cannot create file\n");
exit(1);
}
fwrite(&emp1, sizeof(struct record), 1, fp);
fclose(fp);
fp = fopen("employee.dat", "rb");
fread(&emp2, sizeof(struct record), 1, fp);
printf("Read from binary file:\n");
printf("ID: %d\n", emp2.id);
printf("Name: %s\n", emp2.name);
printf("Salary: %.2f\n", emp2.salary);
fclose(fp);
return 0;
}
Important Points to Remember
- Always check if file opened successfully (fp != NULL).
- Close files after use to prevent data loss and free resources.
- When opening a file in "w" mode, existing contents are deleted.
- Use "a" mode to append to existing files without losing data.
- Check for EOF when reading files to avoid infinite loops.
- Use
feof()to test for end-of-file condition. - Random access functions return -1 on error; always check return values.
- Binary files are more efficient for storing structured data.
- Command line arguments are space-separated; use quotes for arguments with spaces.
Chapter Exercises
Review Questions
- State true or false:
a) A file must be opened before it can be used.
b) All files must be explicitly closed.
c) Files are always referred to by name in C programs.
d) Usingfseekto position a file beyond the end is an error.
e) If an existing file is opened in write mode, its contents are deleted.
f) If a non-existent file is opened in read mode, it results in an error.
g) Bothscanf()andfscanf()return the number of items successfully read. - What is the difference between
getc()andgetchar()? - How does append mode differ from write mode?
- What are the common uses of
rewind()andftell()? - Explain the general format of
fseek()function. - What does
while ((c = getchar()) != EOF)do?
Multiple Choice Questions
- Which function is used to write an integer to a file?
a) fprintf()
b) putw()
c) putc()
d) puts() - Which symbol indicates EOF?
a) ^Z
b) ~Z
c) EOF
d) All of these - While reading integer data from a file, EOF is indicated by which value?
a) -1
b) 0
c) -9999
d) None - Which status-enquiry function detects I/O errors?
a) feof()
b) error()
c) ferror()
d) None - The mode _______ is used for opening a file for updating.
a) "r+"
b) "w"
c) "a"
d) "rb"
Debugging Exercises
Find errors in the following code segments:
FILE fptr;
fptr = fopen("data.txt", "r"); // Error?
FILE *fp = fopen("test.txt", "r");
fprintf(fp, "Hello"); // Error?
fclose("data.txt"); // Error?
FILE *fp = fopen("nonexistent.txt", "r");
while (!feof(fp)) {
fgetc(fp); // Error?
}
Programming Exercises
- Write a program to copy the contents of one file to another.
- Two files DATA1 and DATA2 contain sorted lists of integers. Write a program to merge them into a third sorted file. Use command line arguments for file names.
- Write a program that compares two files and returns 0 if they are equal, 1 if not.
- Write a program that appends one file at the end of another.
- Write a program that reads a file containing integers and appends the sum of all integers at the end.
- Write a program that prompts for two files - source and target - and copies source to target, deleting a specified character during copying.
- Write a program that requests a filename and an offset value, then reads and prints the file starting from that offset.
- Write a program to create a sequential file storing product details (code, cost, quantity).
- Write a program to read the file created in Exercise 8 and compute the total value of all products.
- Write a program to store records in a random access file and print alternate records.
- Write a program that uses
getw()to read integers from one file and writes them in reverse order to another. - Write a program that reads characters from a file and prints their ASCII codes.
Interview Questions
- What is the difference between
printf()andfprintf()? - What is the difference between
getc(),getw(), andfscanf()? - What is the purpose of
ftell()function? - What is the purpose of
fseek()function? - What is the difference between
printf()andsprintf()? - What will happen if you try to open a file for reading that doesn't exist?
- How do you test for end-of-file while reading?
- What is the difference between text mode and binary mode?
Case Study: Inventory Management System
📝 Case Study: Complete inventory management with file operations
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct item {
int code;
char name[30];
int quantity;
float price;
};
void add_item() {
FILE *fp;
struct item it;
char ch;
fp = fopen("inventory.dat", "ab");
if (fp == NULL) {
printf("Cannot open file\n");
return;
}
do {
printf("\nEnter item code: ");
scanf("%d", &it.code);
printf("Enter item name: ");
scanf("%s", it.name);
printf("Enter quantity: ");
scanf("%d", &it.quantity);
printf("Enter price: ");
scanf("%f", &it.price);
fwrite(&it, sizeof(struct item), 1, fp);
printf("Add another? (y/n): ");
scanf(" %c", &ch);
} while (ch == 'y' || ch == 'Y');
fclose(fp);
}
void display_all() {
FILE *fp;
struct item it;
int count = 0;
fp = fopen("inventory.dat", "rb");
if (fp == NULL) {
printf("No inventory file found\n");
return;
}
printf("\n%5s %-20s %10s %10s %10s\n",
"Code", "Name", "Quantity", "Price", "Value");
printf("------------------------------------------------\n");
while (fread(&it, sizeof(struct item), 1, fp) == 1) {
printf("%5d %-20s %10d %10.2f %10.2f\n",
it.code, it.name, it.quantity, it.price,
it.quantity * it.price);
count++;
}
printf("------------------------------------------------\n");
printf("Total items: %d\n", count);
fclose(fp);
}
void search_item() {
FILE *fp;
struct item it;
int code, found = 0;
printf("Enter item code to search: ");
scanf("%d", &code);
fp = fopen("inventory.dat", "rb");
if (fp == NULL) {
printf("No inventory file found\n");
return;
}
while (fread(&it, sizeof(struct item), 1, fp) == 1) {
if (it.code == code) {
printf("\nItem found:\n");
printf("Code: %d\n", it.code);
printf("Name: %s\n", it.name);
printf("Quantity: %d\n", it.quantity);
printf("Price: %.2f\n", it.price);
printf("Value: %.2f\n", it.quantity * it.price);
found = 1;
break;
}
}
if (!found)
printf("Item with code %d not found\n", code);
fclose(fp);
}
void update_quantity() {
FILE *fp, *temp;
struct item it;
int code, qty, found = 0;
printf("Enter item code to update: ");
scanf("%d", &code);
printf("Enter new quantity: ");
scanf("%d", &qty);
fp = fopen("inventory.dat", "rb");
temp = fopen("temp.dat", "wb");
if (fp == NULL || temp == NULL) {
printf("File error\n");
return;
}
while (fread(&it, sizeof(struct item), 1, fp) == 1) {
if (it.code == code) {
it.quantity = qty;
found = 1;
}
fwrite(&it, sizeof(struct item), 1, temp);
}
fclose(fp);
fclose(temp);
remove("inventory.dat");
rename("temp.dat", "inventory.dat");
if (found)
printf("Quantity updated successfully\n");
else
printf("Item not found\n");
}
int main() {
int choice;
while (1) {
printf("\n=== INVENTORY MANAGEMENT SYSTEM ===\n");
printf("1. Add Item\n");
printf("2. Display All Items\n");
printf("3. Search Item\n");
printf("4. Update Quantity\n");
printf("5. Exit\n");
printf("Enter your choice: ");
scanf("%d", &choice);
switch (choice) {
case 1: add_item(); break;
case 2: display_all(); break;
case 3: search_item(); break;
case 4: update_quantity(); break;
case 5: exit(0);
default: printf("Invalid choice\n");
}
}
return 0;
}