When reading single bytes from a file in C, one must pay attention to the correct usage of feof() and fread(). At first, the following piece of code seems to work correctly:
const char *filename = "hello"; unsigned char byte; FILE *fp; fp = fopen(filename, "rb"); if (!fp) { printf("could not open file\n"); return 1; } while(!feof(fp)) { fread(&byte, 1, 1, fp); printf("%02x\n",byte); } fclose(fp); |
Suppose the file “hello” has the following contents:
0000000: 68 65 6c 6c 6f 0a hello. |
(which is the string “hello” followed by an LF)
When the code above is run, the following output is produced:
68 65 6c 6c 6f 0a 0a |
Notice the last character seems to be read twice. The problem is that feof() only returns true after attempting to read past the end of the file. In order to fix this “read-twice” behavior, the return value of fread() must be checked:
if(!fread(&byte, 1, 1, fp)) { break; } |
Note: Using feof() as the while condition is kind of redundant here. In this situation, one could simply use while(1) and the behavior would be the same.
4 comments ↓
Yep. I already had troubles with “feof()”. The key thing to remember is that you must use the while as if you were looping with an integer as the iterator like:
int i = 0;
while ( i < 9 ) {
printf(“%d”, i);
i = i + 1;
}
The difference is that you are iterating in a file stream:
unsigned char byte;
fread(&byte, 1, 1, fp);
while ( !feof(fp) ) {
printf(“%c”, byte);
fread(&byte, 1, 1, fp);
}
But, if you compare the two algorithms, you will see the same pattern.
Haha, my post seems totally pointless now. I am going to update it and give you the credit for a much better solution 🙂
Actually your original solution is the better one. If fread fails for reasons other than eof, it will not go to an infinite loop
You should always check the result value of fread/fclose/….
Leave a Comment