• 【被误用的feof与文件操作读取结束的正确判定】


    学习导航

    一、被误用的feof

    从函数的名字来看,大家很容易把函数的功能理解成:检测是是否达到文件的结尾。但事实真的如此吗?我们首先来查阅feof函数的返回值:

    所以可以确定的是,如果feof检测出文件结束志标记则返回一个非零值。但这里需要注意,feof检测的是 “文件结束标记” ,而不是 “文件位置标记” ,这在FILE结构体中属于两种不同的标记。文件到达结尾只是说明文件的位置标记达到末尾,不能说明文件结束标记的情况,而只有文件结束标记才能使feof的返回值为真。
     我们可以用下面的代码来说明上面的结论,预先使test.txt的内容为空。

    int main()
    {
    	FILE* fp = fopen("test.txt", "r");
    	if (fp == NULL)
    	{
    		printf("%s", strerror(errno));
    		return 0;
    	}
    	for (int i = 0; i < 2; i++)
    	{
    		printf("feof() = %d\n", feof(fp));
    		fgetc(fp);
    	}
    	fclose(fp);
    	fp = NULL;
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    打印结果如下:

    feof() = 0;
    feof() = 1;
    可以看到即使到达了文件结尾,feof也不能立刻检测出。那为什么第二次就可以呢?其实原因在于fgetc发挥了作用。根据C标准对该函数的说明,当fgetc返回值为EOF时且确实已经到达文件结尾时(返回值为EOF可能有其他的情况),fgetc函数会自动设置文件结束标记。

    所以换言之,feof函数并不能检测是否达到文件结尾,它只能测出文件读取失败是否由于文件读取结束引起的。文件读取失败对于fgetc函数来说表现在返回值为EOF。

    二、正确的判断方法

    正确的做法是根据函数的返回值来进行判断,现在我们对常用函数进行逐一说明:

    ①fgetc函数

    fgetc函数需要检测返回值是否为EOF
    如果到达文件结尾,文件结束标志被fgetc函数设置,可以通过feof函数检测出
    如果发生读取错误,文件错误标志被fgetc函数设置,可以通过ferror函数检测出

    int main()
    {
    	FILE* fp = fopen("test.txt", "r");
    	if (fp == NULL)
    	{
    		printf("%s", strerror(errno));
    		return 0;
    	}
    	int c = 0;
    	while ((c = fgetc(fp)) != EOF)
    	{
    		putchar(c);
    	}
    	//判断是什么原因结束的
    	if (ferror(fp))
    	{
    		printf("I/O error when reading\n");
    	}
    	else if (feof(fp))
    	{
    		printf("End of file reached successfully\n");
    	}
    	flose(fp);
    	fp = NULL;
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    ②fgets

    fgets函数需要检测返回值是否为NULL
    如果到达文件结尾,文件结束标志被fgets函数设置,可以通过feof函数检测出
    如果发生读取错误,文件错误标志被fgets函数设置,可以通过ferror函数检测出

    ③fread函数

    对于fread函数我们需要检测实际返回的读取个数和预期读取个数
    如果实际读取个数和预期读取个数不同,说明要么发生读取错误,要么达到文件结尾,那么相应的文件错误标志和文件结束标志也被设置。可以通过ferror和feof函数进行检验。

    #define SIZE 5
    int main(void)
    {
    	double src[SIZE] = { 1.0, 2.0, 3.0, 4.0, 5.0 };
    	double buf[SIZE] = {0};
    	FILE* fp = fopen("test.bin", "wb"); // 必须用二进制模式
    	fwrite(src, sizeof(src[0]), SIZE, fp); // 写 double 的数组
    	fclose(fp);
    
    	fp = fopen("test.bin", "rb");
    	size_t ret_code = fread(buf, sizeof(buf[0]), SIZE, fp); // 读 double 的数组
    	if (ret_code == SIZE) 
    	{
    		puts("Array read successfully, contents: ");
    		for (int n = 0; n < SIZE; ++n) 
    			printf("%f ", buf[n]);
    		putchar('\n');
    	}
    	else // error handling
    	{ 
    		if (feof(fp))
    			printf("Error reading test.bin: unexpected end of file\n");
    		else if (ferror(fp)) 
    			perror("Error reading test.bin");
    	}
    	fclose(fp);
    	fp = NULL;
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    三.总结

    **fgetc、fgets、fread才是判断文件是否读取结束的,

    1. 如果fgetc返回EOF则文件读取结束,否则没结束返回当前文件位置标记的ASCII码值。
    2. 如果fgets返回NULL则文件读取结束,否则返回当前文件位置标记的地址
    3. 如果fread返回的实际值即读的实际个数小于预期读的个数说明读取结束,否则没有读取结束**

    但是上面三种方式都只是判断文件是否读取结束,但是并不知道是正常读取结束还是异常导致的读取结束,所以我们要通过feof来判断,如果返回非0值,是正常读取结束,否则是异常读取结束,用ferror来打印错误信息。

    小编制作不易,点个小猪猪,谢谢大家!

  • 相关阅读:
    iOS系统文件备份与还原:保护和管理手机中的关键数据
    支付卡行业(PCI)PIN安全要求和测试程序 7个控制目标、33个要求及规范性附录ABC 密钥注入-PCI认证-安全行业基础篇4
    Ubuntu 20.04安装Anaconda3及使用
    Linux知识点:系统目录结构的理解,环境变量的作用和添加,创建自己的共享库并使用,引用第三方库
    求接毕业设计答辩问答指导
    [数据库与软件工程]四、关系代数之关系除法的实际意义与计算方法
    5G+北斗高精度定位系统适用于哪些行业领域?
    【Python】【OpenCV】关于cv2.findContours()轮廓索引(编号)解析(RETR_TREE)
    Paper reading:Fine-Grained Head Pose Estimation Without Keypoints (CVPR2018)
    客服系统Golang源码
  • 原文地址:https://blog.csdn.net/2301_76560014/article/details/133779965