Files are like notebooks on a shelf β open one, read or write, then put it back.
The Notebook Analogy
Imagine a shelf full of notebooks. To use one, you:
Pull it off the shelf β fopen()
Read pages or write new ones β fprintf(), fscanf(), fgets()
Put it back β fclose()
If the notebook doesn't exist and you try to read it, you'll get a NULL pointer. If you open it for writing, C will create a brand-new notebook for you.
fopen Modes
The second argument to fopen tells C how to open the file:
"r" β Read only. File must exist.
"w" β Write only. Creates file or erases existing content.
"a" β Append. Writes to the end without erasing.
Note: Always check if fopen returns NULL β the file might not exist, you might not have permission, or the disk could be full. Always call fclose when you're done β unclosed files can lose data because writes may be buffered in memory and never flushed to disk.
Reading Line by Line
fgets() reads one line at a time into a buffer you provide. It's the safest way to read text files because you specify a maximum length β no buffer overflow risk.
The loop pattern while (fgets(buffer, size, fp) != NULL) reads until the end of the file. When there's nothing left, fgets returns NULL.
Reading Line by Line with fgets
#include <stdio.h>
int main(){
FILE*fp =fopen("scores.txt","r");
if(fp ==NULL){
printf("Error: cannot open scores.txt\n");
return1;
}
char line[256];
int lineNum =1;
while(fgets(line,sizeof(line), fp)!=NULL){
printf("Line %d: %s", lineNum, line);
lineNum++;
}
fclose(fp);
return0;
}
Output
Line 1: Alice: 95
Line 2: Bob: 87
Line 3: Carol: 92
Binary Files β fread and fwrite
Text files store data as human-readable characters. Binary files store raw bytes β exactly how data looks in memory. This is faster and more compact, but you can't open a binary file in Notepad and make sense of it.
fwrite(data, elementSize, count, fp) writes raw bytes. fread(buffer, elementSize, count, fp) reads them back.
fread returns the number of items actually read β if it's less than you asked for, you've hit EOF or an error
feof(fp) returns true if you've reached the end of the file
ferror(fp) returns true if a read/write error occurred
Robust Error Checking
#include <stdio.h>
int main(){
FILE*fp =fopen("nonexistent.txt","r");
if(fp ==NULL){
perror("fopen failed");
// perror prints the system error message
return1;
}
char buf[100];
while(fgets(buf,sizeof(buf), fp)){
printf("%s", buf);
}
if(ferror(fp)){
printf("A read error occurred!\n");
}elseif(feof(fp)){
printf("Reached end of file.\n");
}
fclose(fp);
return0;
}
Output
fopen failed: No such file or directory
Note: Opening a file with "w" mode will ERASE everything in it! If you want to add to an existing file without destroying its contents, use "a" (append) mode instead.
Challenge
Quick check
What does fopen return if the file cannot be opened?