Linux 文件EOF说明

发布时间 2023-09-06 14:12:05作者: 寒魔影

EOF 的定义

EOF 是 end of file 的缩写,表示”文字流”(stream)的结尾。这里的"文字流",可以是文件(file),也可以是标准输入(stdin)。通过 EOF 可以判断程序是否读取到文件的末尾
Linux 系统一个非常重要的思想就是:一切皆文件。不管是标准输入,文件系统中的普通文本文件,还是网络流都可以看做是文件,都可以通过 read/write 函数进行读写操作。
因此,不同的文件类型,判断是否读取到文件末尾的方式也就有所不同。

EOF 定义在 /usr/include/stdio.h 文件中:

/* End of file character.
Some things throughout the library rely on this being -1.  */
    #ifndef EOF
    # define EOF (-1)
    #endif

普通文件

普通文件存在于 Linux 中的文件系统中,并且文件的大小是固定的。
对于这种文件,Linux 系统判断普通文本文件是否读取到文件末尾的方法是:read 函数会对所打开的文件维护一个读取指针,
然后根据这个指针跟文件开始位置的指针值相减得到一个相对于文件开始位置的偏移字节数,
最后通过这样一个偏移字节数和文件本身的大小进行一个比较,如果相对于文件开始位置的偏移字节数大于文件本身的大小,
那么就返回一个 EOF 常量,说明此时已经读取到文件末尾了。

标准输入文件

标准输入文件(stdin)它对应的是外设键盘输入,而在 Linux 系统中它被抽象成一个文件,准确地说是一个流文件。
这种文件和上面普通文本文件最大的区别就是它的文件大小是不固定的,它就像是一个水管的进水端,可以在任何时候都可以接收输入。
正是因为标准输入文件这种流式的特点,决定了无法通过前面提到那种比较文件大小方法来判断是否读取到了文件末尾。
因此,Linux 系统判断标准输入文件是否读取到文件末尾的方法是:设置一个特殊的输入标记来表示文件末尾,
而在Linux 系统中这个标记就是组合键Ctrl+D,当系统捕获到这个组合键时,就让 read 函数返回一个 EOF 常量,
告知程序已经读取到标准文件的末尾了。

socket 套接字

socket 是从网络上进行数据读取,所以上面两种判断文件是否读取到末尾的方法都不适用于 socket 流文件。
那么客户端进程怎么判断服务端进程是否已经写完所有数据?
在 socket 流文件中,当客户端进程通过 read 函数读取远程服务端进程发送过来的数据时,使用的是阻塞I/O的方式进行读取的。
只要客户端和服务端之间的连接没有断开,如果服务端没有向 socket 写入数据,那么客户端的读操作就会阻塞,直到服务端中写入了新的数据。
如果服务端进程关闭了socket连接,那么客户端会接收到服务端发送过来的一个 TCP 协议的 FIN 数据包,
然后客户端进程中原本阻塞着等待接收服务端进程数据的 read 函数此时就会被唤醒,返回一个值 0。
这跟我们前面提到两种文件读到文件末尾返回 EOF(值为-1)的情况有点差别,所以在程序中从 socket 进行读取操作时,
判断数据流结束的标志不是 -1 而是 0。