Chapter 17: File System and I/O Operations
In Unix-like systems (and by extension C), "everything is a file." Whether you are writing to a hard drive, a keyboard, or a network socket, the C standard library provides a unified interface for Input/Output (I/O).
I. Streams and the FILE Pointer
C uses Streams to handle I/O. A stream is an abstraction that represents a flow of data. The standard library uses the FILE * type to manage these streams.
Standard Streams
stdin: Standard Input (Keyboard)stdout: Standard Output (Console)stderr: Standard Error (Console, for error messages)
II. Working with Files
The basic lifecycle of file I/O involves: Open -> Process -> Close.
#include <stdio.h>
int main() {
FILE *fptr;
fptr = fopen("data.txt", "w"); // Open for writing
if (fptr == NULL) {
perror("Error opening file");
return 1;
}
fprintf(fptr, "Hello File System!\n");
fclose(fptr); // Crucial to flush buffers and release handles
return 0;
}
Common Modes for fopen
"r": Read (fails if file doesn't exist)."w": Write (creates file or overwrites)."a": Append (adds to end of file)."r+": Read and Write.
III. Formatted vs. Character I/O
- Formatted:
fprintfandfscanf. Use these for text data where you want to read/write numbers and strings. - Character:
fgetcandfputc. Process one character at a time. - Line:
fgetsandfputs. Read/write an entire line. Avoidgets()as it is highly insecure.
IV. Binary I/O: fread and fwrite
When working with images, audio, or database records, you don't want to translate data to text. You want to write raw bytes.
struct Record { int id; float value; };
struct Record r = {1, 99.5f};
// Write a whole struct directly to disk
fwrite(&r, sizeof(struct Record), 1, fptr);
V. Random Access: fseek and ftell
You can move the "file pointer" to any byte position in the file.
fseek(fp, offset, origin): Move to a position.SEEK_SET(start),SEEK_CUR(current),SEEK_END(end).ftell(fp): Get the current byte position.
VI. Error Handling: feof and ferror
Always check for the end-of-file (feof) and potential disk errors (ferror). Using perror prints a human-readable error message based on the global errno variable.