Usage of fopen modes r, r+, w, w+, a and a+
Background
I did the following operations, but got an unexpected result.
- Use fopen function to open a file.
- Use fprintf function to write two integers to this file.
- Use fscandf function to read the integers.
- Got NULL.
After I have analysed the reason, I found it was related to fopen modes, so I am going to write this article to introduce the detalied difference between fopen modes r, r+, w, w+, a, a+.
Introduction
Prototype of fopen:
FILE *fopen(const char *restrict pathname, const char *restrict type);
The options for type parameter:
Type | Description | Open(2) flags |
r, rb | open for reading | O_RDONLY |
w, wb | Truncate the file to 0 length, or created for writing | O_WDONLY|O_CREAT|O_TRUNC |
a, ab | Append: Open for writing at the end of a file, or created for writing | O_WDONLY|O_CREAT|O_APPEND |
r+, rb+, r+b | Open for reading and writing | O_RDWR |
w+,wb+,w+b | Truncate a file to 0, or open it for reading and writing | O_RDWR|O_CREAT|O_TRUNC |
a+,ab+, a+b | Opens and creation for end-of-file reading and writing | O_RDWR|O_CREAT|O_APPEND |
Below is my code and understanding the above parameters by changing the parameters.
#include <stdio.h> int main() { FILE *fp = NULL; if ((fp = fopen("data.txt", "w+")) == NULL) { printf("open file error\n"); } int a = 2, b = 3; int cnt = -1, cnt1 = -1; long pos = -1; fprintf(fp, "%d %d\n", a, b); //fseek(fp, 0, SEEK_SET); fscanf(fp, "%d %d", &cnt, &cnt1); pos = ftell(fp); printf("pos = %ld\n", pos); printf("%d %d\n", cnt, cnt1); fclose(fp); return 0; }
Case 1: “w”
Modify the above code from “fp = fopen(“data.txt”, “w+”)” to “fp = fopen(“data.txt”, “w”)“.
Write only. If the file does not exist, it will be created automatically. And the cursor position is moved after the write.
Output:
$ ./a.out
pos = 4
-1 -1
Because “w” is only for write and the current position is 4 rather than 0, so we can’t read the a, b integers.
Case 2: “r”
Modify the above code from “fp = fopen(“data.txt”, “w+”)” to “fp = fopen(“data.txt”, “r”)“.
Read only. If the file does not exist at this time, it will not be created automatically and fopen will fail.
Output:
$ ./a.out
pos = 4
-1 -1
Even if we changed the type from “w” to “r”, we still can’t read the data because the current position is also 4.
We can use fseek to change the current position to 0 and read the data again.
Removed the annotation on “fseek(fp, 0, SEEK_SET);” in the above code.
Output:
pos = 3
2 3
Now, we can read the data because the current position is 0 before reading.
Case 3: “rw”
There is no such mode, this mode will fail to write.
Case 4: “r+” 和 “w+”
Modify the above code from “fp = fopen(“data.txt”, “w+”)” to “fp = fopen(“data.txt”, “r+”)” or no changes.
Output:
$ ./a.out
pos = 4
-1 -1
Though “r+” and “w+” mean read and write, they also can’t read the data because the current position is not 0.
Note:
- If you want to open a binary file, you need to add “b” in type parameter. If not, you don’t need to add “b”.
- The addition of a “+” indicates that both “r+” and “w+” are read-write, and the cursor will move backward. So if you want to fetch data, you need to use the fseek() function to point the cursor to the starting position.Fseek (fp, 0, SEEK_SET) after fprintf.
Related articles:
[Solution]what is the format for printf to print unsigned char itself?
Any feedbacks are welcome.