1. 程式人生 > >檔案流中讀行的正確使用(fgets、feof、ferror)

檔案流中讀行的正確使用(fgets、feof、ferror)

char *fgets(char *buf, int bufsize, FILE *stream);

功能

fgets函式用來從stream所指檔案中讀入bufsize-1個字元放入buf為起始地址的空間內;如果在未讀滿bufsize-1個字元之時,已讀到一個換行符或一個EOF(檔案結束標誌),則結束本次讀操作,讀入的字串中最後包含讀到的換行符。因此,呼叫fgets函式時,最多隻能讀入bufsize-1個字元。讀入結束後,系統將自動在最後加’\0’,並以buf作為函式值返回。

返回值

  • 成功,則返回第一個引數buf;
  • 在讀字元時遇到end-of-file,則eof指示器被設定,如果還沒讀入任何字元就遇到這種情況,則buf保持原來的內容,返回NULL;
  • 如果發生讀入錯誤,error指示器被設定,返回NULL,buf的值可能被改變。

stream檔案流指標體指向檔案內容地址的偏移原則

  • 如果使用fgets()讀取某個檔案,第一次讀取的bufsize為5,而檔案的第一行有10個字元(算上’\n’),那麼讀取檔案的指標會偏移至當前讀取完的這個字元之後的位置。也就是第二次再用fgets()讀取檔案的時候,則會繼續讀取其後的字元。
  • 如果使用fgets() 讀取檔案的時候bufsize大於該行的字元總數加2(多出來的兩個,一個儲存檔案本身的’\n’換行,一個儲存字串本身的結束標識’\0’),檔案並不會繼續讀下去,僅僅只是這一行讀取完,隨後指向檔案的指標會自動偏移至下一行。
int feof(FILE *stream);

功能
feof是檢測流上的檔案結束符,如果檔案結束,則返回非0值,否則返回0,檔案結束符只能被clearerr()清除。

int ferror(FILE *stream);

功能
在呼叫各種輸入輸出函式(如 putc.getc.fread.fwrite等)時,如果出現錯誤,除了函式返回值有所反映外,還可以用ferror函式檢查。如果ferror返回值為0,表示未出錯。如果返回一個非零值,表示出錯。
對同一個檔案每一次呼叫輸入輸出函式,均產生一個新的ferror函式值,因此,應當在呼叫一個輸入輸出函式後立即檢查ferror函式的值,否則資訊會丟失。

在執行fopen函式時,ferror函式的初始值自動置為0。

例子
1.txt2.txt

int main(void) {
    char line[256];
    FILE *f = fopen("1/2.txt", "rb");
    while (!feof(f)) {
        fgets(line, sizeof(line), f);
        printf("-%s", line);
    }
    fclose(f);
    return 0;
}

1.txt:
1.txt
2.txt:
2.txt

原因:
fgets在讀取了sizeof(line)-1個字元、讀到了’\n’或遇到了EOF三種情況之一時都結束讀取。 2.txt多餘的一行列印,是因為2.txt最後一行只有一個’\n’,fget讀一個位元組立即正常結束讀取,此種情況下未更新line內容導致。

改進:
5.txt

推薦寫法:

int main(void) {
    char line[256];
    FILE *f = fopen("2.txt", "rb");
    while (!feof(f) && !ferror(f)) {
        strcpy(line, "\n"); 
        fgets(line, sizeof(line), f);
        printf("-%s", line);
    }
    fclose(f);
    return 0;
}