fseek、ftell和rewind函數,C語言fseek、ftell和rewind函數詳解

2020-07-16 10:04:25
對於檔案的讀寫方式,C 語言不僅支援簡單地順序讀寫方式,還支援隨機讀寫(即只要求讀寫檔案中某一指定的部分)。對順序讀寫方式來說,隨機讀寫方式需要將檔案內部的位置指標移動到需要讀寫的位置再進行讀寫,這通常也被稱為檔案的定位

對於檔案的定位,可以通過 rewind、fseek 與 ftell 函數來完成。

其中,rewind 函數用於將檔案內部的位置指標重新指向一個流(資料流或者檔案)的起始位置。這裡需要注意的是,這裡的“指標”表示的不是檔案指標,而是檔案內部的位置指標。即隨著對檔案的讀寫,檔案的位置指標(指向當前讀寫位元組)向後移動。而檔案指標指向整個檔案,如果不重新賦值,檔案指標不會發生改變。

rewind 函數的一般原型如下所示:

void rewind(FILE *fp);

從上面的函數原型可以看出,rewind 並沒有返回值,因此也無法做安全性檢查。如下面的範例程式碼所示:
FILE *fp=NULL;
fp=fopen("Test.txt","r");
if(fp==NULL)
{
}
rewind(fp);
在上面的範例程式碼中,由於 rewind 函數沒有返回值,所以我們很難判斷“rewind(fp)”是否執行成功。因此,應該盡量使用 fseek 來替換 rewind 函數,從而以驗證流已經成功地回繞。如下面的範例程式碼所示:
if (fseek(fp, 0L, SEEK_SET) != 0)
{
}
相對於 rewind 函數而言,fseek 函數的功能更加強大,它用來設定檔案的當前讀寫位置,從而可以實現以任意順序存取檔案的不同位置,以實現檔案的隨機存取。其函數的一般原型如下所示:

int fseek(FILE *fp,long offset,int from);

如果該函數執行成功,fp 將指向以 from 為基準,偏移 offset 個位元組的位置,函數的返回值為 0;如果該函數執行失敗(比如 offset 超過檔案自身大小),則不改變 fp 指向的位置,函數的返回值為 -1,並設定 errno 的值,可以用 perror 函數來輸出錯誤資訊。

對於 fseek 函數中的引數:第一個引數 fp 為檔案指標;第二個引數 offset 為偏移量,它表示要移動的位元組數,整數表示正向偏移,負數表示負向偏移;第三個引數 from 表示設定從檔案的哪裡開始偏移,取值範圍如表 1 所示。

表 1 from引數取值表
起始點 表不符號 數位表示
檔案首 SEEK_SET 0
當前位置 SEEK_CUR 1
檔案末尾 SEEK_END 2

由表 1 可知:
  • SEEK_SET 表示從檔案起始位置增加 offset 個偏移量為新的讀寫位置;
  • SEEK_CUR 表示從目前的讀寫位置增加 offset 個偏移量為新的讀寫位置;
  • SEEK_END 表示將讀寫位置指向檔案尾後,再增加 offset 個偏移量為新的讀寫位置。

當 from 值為 SEEK_CUR 或 SEEK_END 時,引數 offset 允許出現負值。如下面的範例程式碼所示:
/*將讀寫位置移動到離檔案開頭100位元組處*/
fseek(fp,100L,0);
/*將讀寫位置移動到離檔案當前位置100位元組處*/
fseek(fp,100L,1);
/*將讀寫位置退回到離檔案結尾100位元組處*/
fseek(fp,-100L,2);
/*將讀寫位置移動到檔案的起始位置*/
fseek(fp,0L,SEEK_SET);
/*將讀寫位置移動到檔案尾*/
fseek(fp,0L,SEEK_END);
不難發現,上面的語句“(void)fseek(fp,0L,SEEK_SET);”的作用實際上等同於 rewind 函數。與此同時,在使用 fseek 函數時,還應該注意如下 3 點。
  1. 首先,呼叫 fseek 函數的檔案指標 fp 應該指向已經開啟的檔案,否則將會出現錯誤。
  2. 其次,fseek 函數一般用於二進位制檔案,當然也可以用於文字檔案。需要特別注意的是,當 fseek 函數用於文字檔案操作時,一定要注意回車換行的情況。因為在一般瀏覽工具(如 UltraEdit)中,回車換行被視為兩個字元 0x0D 和 0x0A,但真實的檔案讀寫和定位卻按照一個字元 0x0A 進行處理。因此,在碰到此類問題時,可以考慮將檔案整個讀入記憶體,然後在記憶體中手工插入 0x0D的方法,這樣可以達到較好的處理效果。
  3. 最後,fseek 函數隻返回執行的結果是否成功,並不返回檔案的讀寫位置。因此,你可以使用 ftell 函數來取得當前檔案的讀寫位置。

ftell 函數的原型為:

long ftell(FILE *fp);

該函數用於得到檔案位置指標當前位置相對於檔案首的偏移位元組數。在隨機方式存取檔案時,由於檔案位置頻繁前後移動,程式不容易確定檔案的當前位置。在使用 fseek 函數後,再呼叫函數 ftell 就能非常容易地確定檔案的當前位置。如下面的範例程式碼所示:
long getfilelength(FILE *fp)
{
    long curpos=0L;
    long length=0L;
    curpos = ftell(fp);
    fseek(fp, 0L, SEEK_END);
    length = ftell(fp);
    fseek(fp, curpos, SEEK_SET);
    return length;
}