函数 feof() 用来检测流上的文件结束符。函数声明如下:
[C++] 纯文本查看 复制代码
#include <stdio.h>
int feof(FILE *stream);
feof(fp)有两个返回值:如果遇到文件结束,函数 feof() 就返回非零值,否则为0。
EOF 是文件结束标志的文件。在文本文件中,数据是以字符的 ASCII 代码值的形式存放,ASCII 代码的范围是 0 到 127,如下图所示:
![]()
ASCII 码并没有规定编号为 128~255 的字符,为了能表示更多字符,各厂商制定了很多种ASCII码的扩展规范。注意,虽然通常把这些规范称为扩展ASCII码(Extended ASCII),但其实它们并不属于ASCII码标准。例如以下这种扩展ASCII码由IBM制定,在字符终端下被广泛采用,其中包含了很多表格边线字符用来画界面,如下图所示:
![]()
由上图可见,255 时并没有定义什么字符,所以在对数据进行字符形式存取时,不可能回遇到 -1 这种情况,所以将 -1 当成是 EOF,也就是说,当读到 -1 时,就认为读取文件结束。
测试代码:
[C++] 纯文本查看 复制代码 #include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char *argv[])
{
FILE *fp;
char combuf[512];
char *pbuf = combuf;
if (!(fp = fopen(argv[1], "r"))) {
perror ("fopen error");
exit (EXIT_FAILURE);
}
memset (combuf, 0, 512);
while (!feof(fp)) {
*pbuf++ = fgetc (fp);
}
fclose(fp);
printf ("%s\n", combuf);
return (0);
}
上面代码用以读取一个简短的普通文本文件(通过 echo "hello world" > test.txt 得到)到数组,然后输出。在读取文件中,我们一次读取一个字符,并且用 feof() 函数判断是否读取到末位。下面运行该程序查看会有什么问题:$ ./readtest test.txt
hello world
� 我们看到最后最后输出了一个乱码符。这个乱码字符串实际就是 EOF,十六进制表示为 0xff,八进制即 o377,十进制 -1 。如果用 gdb 调试时可以看到数组内存中 EOF 被读入的值为 \377 。
feof() 函数的停止条件是通过判断文件流指针是否到达 EOF 来决定的。
先来看 fgetc() 函数,根据对上面程序的调试观察与 man 手册中的说明, fgetc() 并不是如一些人所说一次读取一个字节,并在读完之后将文件流指针自动移动到下一个字节处。实际情况是,fgetc() 读取当前文件流指针所指字符的下一个字符,然后文件流指针再移动到该被读取的字符上。
另外,使用 echo "hello world" 这种方式到一个普通文本时,会在 "hello world" 的末位自动添加上一个换行符 '\n' 以及结束符 EOF。所以,当 fgetc() 将换行符 '\n' 读入数组时,文件流指针是指向 '\n' 的,因此这时 feof() 函数会判断还没到达文件尾,所以当下一次读取时,fgetc() 会读入 EOF,同时 feof() 也会结束 while 循环。
从上面分析可以知道为什么会输出一个乱码符号。修正这种现象,可以在 fclose() 函数之前添加一句 *(pbuf - 1) = '\0'; 以显式的去掉 EOF 符号。 |