文件操作 之 踩坑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,也就是一下次寫入的位置,如下圖


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM