概述
我们在使用C标准I/O时,经常会看到EOF这个概念,这里需要明确的是并不存在EOF这样一个字符,它只是一个控制条件。起初,我认为EOF就是字面意思即,到达了文件的结尾(End of File)。可是,最近在看K&R时,发现函数返回时EOF表示的是当前函数调用出现了错误,这些错误包括:
- 文件达到了末尾;
- 文件读写出现了错误,比如,磁盘没有空间。
下面是man中,关于fgetc的解释:
fgetc() reads the next character from stream and returns it as an unsigned char cast to an int, or EOF on end of file or error.
下面是EOF的定义:
#define EOF (-1)
下面通过一个示例讲解一下EOF的用法。
读取一个字符
fgetc这个函数每次从文件流中读取一个,其函数原型如下:
int fgetc(FILE *stream);
这个函数需要的注意地方有几点:
- 每次调用其都返回stream流的下一个字符。
- 函数返回类型为unsigned char(强制类型转换为int),正常情况下,是一个大于0的整数。
- 如果到达文件末尾或发生错误,则返回EOF,通过feof和ferror区分是到达了文件末尾还是发生了错误。
下面举一个关于fgetc的例子,其每从标准输入读取一个字符,并输出到标准输出,直到1)到达文件末尾;2)遇到错误。
#include <stdio.h> int main(void) { int c; while ((c = fgetc(stdin)) != EOF) { fputc(c, stdout); } if (feof(stdin)) { fprintf(stdout, "end of file.\n"); } if (ferror(stdin)) { fprintf(stderr, "some error ocurred.\n"); } return 0; }
lhl@ubuntu20:~/work/BLOGS/C/io$ ./eof hello hello ^D //使用Ctrl+D模拟达到文件末尾 end of file.
Unix I/O EOF?
Unix I/O中的read函数如何表示一个文件到达了文件的末尾了呢?下面是man中关于read返回值的解释:
#include <unistd.h> ssize_t read(int fd, void *buf, size_t count); On success, the number of bytes read is returned (zero indicates end of file), and the file position is advanced by this number. It is not an error if this number is smaller than the number of bytes requested; this may happen for example because fewer bytes are ac‐tually available right now (maybe because we were close to end-of-file, or because we are reading from a pipe, or from a terminal), or because read() was interrupted by a signal. See also NOTES. On error, -1 is returned, and errno is set appropriately. In this case, it is left unspecified whether the file position (if any) changes.
这里有几点需要注意:
- read正常情况下,返回读取的字节数量;
- **0表示文件到达了末尾,Enf of File,Unix I/O EOF仅仅表示文件到达了末尾。
- 返回值大于0,但小于count是正常的,表示文件剩余的字数量就是这么多;
- -1,表示read执行遇到到了错误,比如,被信号中断等。
网络编程中的EOF
网络编程中也会经常遇到EOF这样一个概念,确切的说EOF是由内核检测到的一种条件。上一节说了,当read返回0时,表明文件到达了末尾,网络编程也是类似的,当应用程序接收到一个由read返回的0值之后,它就会认为遇到了EOF这个条件,从而做出相应的处理。对于TCP连接来说,当一个进程主动关闭连接的一端时,本地read就会发出EOF信号,连接的另一端的进程在试图读取流中最后一个字节之后的字节时,会检测到EOF。