What are the different fopen() modes and when do you use each?
fopen(const char *path, const char *mode) opens a file and returns a FILE * stream. The mode string controls read/write access and how the file is created or truncated.
Text modes:
| Mode | Description | File exists | File missing |
|---|---|---|---|
"r" |
Read only | Opens | Returns NULL |
"w" |
Write only (truncates) | Truncates to 0 | Creates new |
"a" |
Append only | Appends at end | Creates new |
"r+" |
Read + write | Opens | Returns NULL |
"w+" |
Read + write (truncates) | Truncates to 0 | Creates new |
"a+" |
Read + append | Opens (writes at end) | Creates new |
Binary modes: Add b to any mode: "rb", "wb", "ab", "r+b" (or "rb+"), etc.
- On Unix/Linux: binary and text modes are identical
- On Windows: text mode translates
\nto\r\nand treats Ctrl+Z as EOF; binary mode does not
C11 exclusive mode: "wx", "wbx" -- fails if file already exists (prevents accidental overwrite). Like O_CREAT | O_EXCL in POSIX.
Critical rule: Always check the return value for NULL.
Read existing file: fopen("data.txt", "r")
Create/overwrite file: fopen("data.txt", "w")
Append to file: fopen("data.txt", "a")
Read + write existing: fopen("data.txt", "r+")
Create + read/write: fopen("data.txt", "w+")
Binary read: fopen("data.bin", "rb")
Binary write: fopen("data.bin", "wb")
Exclusive create (C11): fopen("data.txt", "wx")
#include <stdio.h>
int main(void) {
FILE *fp;
/* Write mode: creates or truncates */
fp = fopen("test.txt", "w");
if (!fp) { perror("fopen w"); return 1; }
fprintf(fp, "Line 1\n");
fprintf(fp, "Line 2\n");
fclose(fp);
/* Append mode: adds to end */
fp = fopen("test.txt", "a");
if (!fp) { perror("fopen a"); return 1; }
fprintf(fp, "Line 3\n");
fclose(fp);
/* Read mode: reads existing */
fp = fopen("test.txt", "r");
if (!fp) { perror("fopen r"); return 1; }
char buf[100];
while (fgets(buf, sizeof(buf), fp)) {
printf("%s", buf);
}
/* Output: Line 1\nLine 2\nLine 3 */
fclose(fp);
/* Read+Write mode */
fp = fopen("test.txt", "r+");
if (!fp) { perror("fopen r+"); return 1; }
fprintf(fp, "MODIFIED"); /* overwrites first 8 bytes */
fclose(fp);
/* Binary mode */
fp = fopen("data.bin", "wb");
if (!fp) { perror("fopen wb"); return 1; }
int nums[] = {1, 2, 3, 4, 5};
fwrite(nums, sizeof(int), 5, fp);
fclose(fp);
/* Cleanup */
remove("test.txt");
remove("data.bin");
printf("All modes demonstrated successfully\n");
return 0;
}
- •"r" reads existing; "w" creates/truncates; "a" appends; + adds the other direction
- •Always check fopen return for NULL before using the FILE pointer
- •Binary mode ("rb"/"wb") matters on Windows (no \r\n translation)
- •On Unix, binary and text modes are identical
- •"wx" (C11) fails if file exists -- prevents accidental overwrite
- •"w" destroys existing file contents immediately on open -- there is no undo
- •"a" mode always writes at end, even after fseek -- you cannot overwrite earlier content
- •Forgetting to check fopen return for NULL leads to NULL pointer dereference crash
- •On Windows, reading binary files in text mode corrupts data (\r\n translation and Ctrl+Z EOF)