Chapter Summary
This chapter introduced file input/output (I/O) operations in C, enabling programs to read from and write to files for persistent data storage. File operations are essential for working with large datasets that cannot be interactively entered and for preserving program output beyond a single execution.
Key Concepts
File Pointers and File Handles
- File Pointer: A variable of type
FILE*that serves as a handle to an open file - Declaration Syntax:
FILE* variableName; - Purpose: Allows a program to reference and interact with a specific file
Opening Files with fopen()
- Function Signature:
FILE* fopen(const char* filename, const char* mode); - Parameters:
filename: A string containing the path to the filemode: A string specifying how the file should be accessed
- Return Value: A
FILE*pointer if successful;NULLif the operation fails - File Access Modes:
"r"(Read): Opens an existing file for reading; file must exist"w"(Write): Opens a file for writing; truncates (empties) existing file or creates new file"a"(Append): Opens a file for writing at the end; preserves existing content or creates new file
- Error Checking: Always verify that
fopen()succeeded by checking if the returned pointer is notNULLbefore attempting file operations
Reading from Files
fgets() Function
- Function Signature:
char* fgets(char* str, int size, FILE* fileHandle); - Purpose: Reads an entire line from a file into a string buffer
- Parameters:
str: Character array where the line will be storedsize: Maximum number of characters to read (including null terminator)fileHandle: File pointer to read from
- Return Value: Pointer to the string if successful;
NULLif end-of-file is reached - Behavior: Includes the newline character (
\n) in the string if present - Use Case: Ideal for reading unstructured text data line-by-line
fscanf() Function
- Function Signature:
int fscanf(FILE* fileHandle, const char* format, ...); - Purpose: Reads formatted data from a file using format specifiers
- Parameters:
fileHandle: File pointer to read fromformat: Format string with specifiers and optional regular expressions- Additional arguments: Pointers to variables where data will be stored
- Return Value: Number of successfully read items; useful for detecting end-of-file or read failures
- Regular Expressions: Format codes using
[]notation to match specific character patterns%[^\n]: Matches any string up to but not including a newline%[^,]: Matches any string up to but not including a comma
- Use Case: Ideal for reading structured data with known format patterns
Writing to Files
fprintf() Function
- Function Signature:
int fprintf(FILE* fileHandle, const char* format, ...); - Purpose: Writes formatted data to a file, similar to
printf()but targets a file - Parameters:
fileHandle: File pointer to write toformat: Format string with specifiers (same asprintf())- Additional arguments: Values to be formatted and written
- Behavior: Works identically to
printf()except output goes to a file instead of the screen - Use Case: Writing structured or formatted data to files
Closing Files with fclose()
- Function Signature:
int fclose(FILE* fileHandle); - Purpose: Closes a file and releases associated system resources
- Parameters:
fileHandle- File pointer to close - Return Value: 0 if successful; non-zero if an error occurs
- Critical Importance:
- Flushes buffered data to disk (ensures data is actually written)
- Frees system resources
- Prevents accidental further access to the file
- Best Practice: Always close files when finished; failure to close can result in data loss and resource leaks
Common File I/O Patterns
Pattern 1: Read Entire File Line-by-Line
FILE *fp = fopen("file.txt", "r");
int rc = 0;
if (fp == NULL) {
printf("Error opening file\n");
rc = 1;
}
char line[256];
while (fgets(line, sizeof(line), fp) != NULL) {
// Process line
}
fclose(fp);
Pattern 2: Read Entire File Character-by-Character
FILE *fp = fopen("file.txt", "r");
int rc = 0;
if (fp == NULL) {
printf("Error opening file\n");
rc = 1;
}
int ch;
while ((ch = fgetc(fp)) != EOF) {
// Process character
}
fclose(fp);
Pattern 3: Read Structured Data
FILE *fp = fopen("data.txt", "r");
int rc = 0;
if (fp == NULL) {
printf("Error opening file\n");
rc = 1;
}
int id;
char name[50];
while (fscanf(fp, "%d %s", &id, name) == 2) {
// Process record
}
fclose(fp);
Working with Structured Data Files
- Struct Definition: Create structs to represent the logical structure of records in a file
- Array of Structs: Use arrays of structs to store multiple records read from a file
- Format Specification: Design
fscanf()format strings to match the exact layout of data in the file - Lazy Evaluation: When using
&&in loop conditions, place bounds checking first to prevent out-of-bounds array access before attempting file operations - Return Values: Functions that read files should return the number of records successfully read to indicate completion and success
End-of-File Detection
- fgets(): Returns
NULLwhen end-of-file is reached - fscanf(): Returns the number of items successfully read; returns fewer items than expected at end-of-file
- feof(): Function that indicates whether a preceding input operation encountered the end-of-file marker
- Proper Detection: Use the appropriate method based on which function is being used for file reading