文件操作 之 踩坑feof()函数和ftell()函数——C语言

踩坑一:feof函数

 

函数原型:int feof( FILE *stream );

函数功能:如果读取操作尝试读取超过文件末尾的位置,feof函数返回非0,否则返回0(函数 feof 只用于检测流文件)

微软官方文档中关于feof描述:

部分翻译:当超过文件末尾时,读取操作返回文件结束指示符,直到流关闭或调用rewind,fsetpos,fseek或clearerr为止。例如,如果文件包含10个字节,你从文件中读取了10个字节,feof会返回0,

因为虽然文件指针在文件的末尾,但是你没有尝试读取超过文件的末尾,只有在你尝试读取第11个字节之后feof函数才会返回非零值

 

换个说法就是:当文件内部位置指针指向文件末尾时,并未立即置位 FILE 结构中的文件结束标记,只有再执行一次读文件操作,才会置位结束标志,此后调用 feof 才会返回为真请读者注意下这句话:只有再执行一次读文件操作,才会置位结束标志”

下面用断点调试来测试feof的返回值:

测试代码:

 

测试文本文件:

 测试结果和运行结果:

从上面的测试结果可以看出,文本文件中只有三个数字,但循环却执行了四次,在第三次循环时读取了第三个数字后,文件内部的位置指针指向了文件末尾,但是此时用feof函数判断的结果仍然为0,并不会跳出循环,

只有当第四次循环中再用fscanf_s读取一次文件内容之后(此时fscanf_s的返回值是-1,也就是说读取是失败的,这也就是为什么第四次循环的ch的值没有变化),再用feof判断才会返回EOF(-1)

按照上面这种“先判断、再读取”写法,如果一个文件含有n个字符,那么while循环的内部操作会运行n+1次,如果不想多循环一次那么需要在while循环内部增加判断语句或者改成“先读取、再判断”

改法一:(while内部增加判断)

 

改法二:(while内部增加判断)

 改法三:(先读取再判断)

 

 

 

踩坑二:ftell函数

 

函数原型:long ftell(FILE *fp);

函数功能:若函数调用成功,则返回文件位置指针当前位置相对于文件首的偏移字节数,否则返回-1L,(对于文本文件来说ftell的返回值是当前位置指针相对于文件起始位置的字节偏移量)

问题一:如果以追加读写的方式打开一个文本文件(文件内容为123),不进行任何I/O操作然后用ftell取得当前文件指针位置,请问ftell返回值为多少?

在微软的官方文档中有这样一段话:

 

 红框中句子的意思:(当以追加的方式打开文件,在发生任何写入操作前文件指针移动到文件的末尾),如果以追加的方式打开文件且没有发生任何I/O操作,则文件指针在文件的开头,鉴于本人英语水平有限没怎么读懂这句话

,感觉有点矛盾,下面就用断点调试来解答问题一

文本文件:

打开方式:

调试结果:

从上面的调试结果可以看出,当以追加读写的方式打开文件时,在未发生任何I/O操作时ftell的返回值为0,意思是文件指针在文件开头,这个在文件开头的指针是下一次读取的位置,而不是下一次写入的位置(写入的位置在文件的末尾),意思是如果是用fscanf_s读取字符,那么读取的字符就是第一个字符,如果是写入字符那么就是在文件的最后一个字符的后一位写入(就是文件的末尾),下面放一张图方便理解

 

再回到上面那句话, (当以追加的方式打开文件,在发生任何写入操作前文件指针移动到文件的末尾),如果以追加的方式打开文件且没有发生任何I/O操作,则文件指针在文件的开头这句话的前半句说的在文件末尾的

文件指针指的是写入的指针,而在文件开头的指针是读取的指针并不是说读取和写入用的两个不同的指针,是同一个指针,如果是两个不同的指针的话那么无法确定ftell是返回的读指针还是写指针的位置

意思是如果以追加读写的方式打开文件,如果发生读操作那么读取的是第一个字符,如果发生写操作那么写入的位置是文件的末尾(也就是最后一个字符的后一位)

 

补充:如果以上面为前提发生了一次写入操作,此时ftell的返回值为多少?

测试文件:

测试代码:

 

断点调试结果:

从上面断点调试的结果可以看出,ftell在发生I/O操作前返回值是0,也就是下一次读取的位置,在发生一次写入操作后,ftell的返回值是4,也就是一下次写入的位置,如下图

posted @ 2019-04-03 21:34  Luv3  阅读(3591)  评论(0编辑  收藏  举报