HOWTO · C
在 C 語言中使用 fscanf 逐行讀取檔案
本文演示瞭如何在 C 語言中使用 fscanf 逐行讀取檔案。
本頁內容
fscanf 會從 FILE 串流讀取格式化輸入。掃描集可以讀取直到換行符號前的字元,但與專用的逐行讀取函式不同,它需要明確處理空白行與有長度上限的區塊。讀取一般文字檔時,fgets 通常更簡單;當輸入格式需要轉換時,再使用 fscanf。
在 C 語言中使用 fscanf 逐行讀取檔案
這個完整範例會建立暫存檔、寫入兩行範例文字,再使用掃描集讀取串流,並將讀取寬度限制在 16 位元組的目的緩衝區內。程式會將讀取到的內容逐行印出。程式區塊中的輸出文字維持英文,以符合程式碼逐位元組一致的要求。
#include <stdio.h>
int main(void) {
FILE *file = tmpfile();
char line[16];
if (file == NULL) {
return 1;
}
if (fputs("First line.\nSecond line.\n", file) == EOF || ferror(file)) {
fclose(file);
return 1;
}
if (fflush(file) == EOF || ferror(file)) {
fclose(file);
return 1;
}
rewind(file);
for (;;) {
int result = fscanf(file, "%15[^\n]", line);
if (result == 1) {
int ch;
puts(line);
ch = fgetc(file);
if (ch == '\n') {
continue;
}
if (ch == EOF) {
break;
}
ungetc(ch, file);
while ((ch = fgetc(file)) != '\n' && ch != EOF) {
}
if (ch == EOF) {
break;
}
continue;
}
if (result == EOF) {
break;
}
if (fgetc(file) == '\n') {
puts("");
}
}
fclose(file);
return 0;
}
寬度設為 15,可在 line 中為結尾的空字元保留空間。每次掃描集轉換成功後,程式都會檢查是否遇到換行符號。如果某行超出緩衝區容量,程式會丟棄該行剩餘內容,再讀取下一行;這樣能限制記憶體用量,但無法完整保留過長的那一行。若掃描集在換行符號前找不到任何符合的字元,迴圈會消耗該換行符號並印出空白行,而不是在沒有進展的情況下重試。正式程式也應在輸入結束後檢查 ferror(file),以區分讀取錯誤與正常的檔案結尾。
使用 fscanf 讀取以空白字元分隔的詞元
解析詞元時,%255s 會將一個非空白詞元讀入 char token[256] 緩衝區。寬度限制可避免寫入超出陣列範圍;%s 會略過前置空白,並在遇到下一個空白字元時停止。迴圈只應在 fscanf(file, "%255s", token) == 1 時繼續;若只檢查 EOF,轉換失敗且未消耗輸入時,可能會造成無限重複。這種做法會刻意把空格、定位字元與換行符號都視為分隔符,因此不會保留原本的行界線。讀取數值欄位時,請使用相符的轉換指定符,並檢查成功指派的欄位數。
使用 fgets 可靠地逐行讀取
若文字中的每筆記錄都是一行,fgets(buffer, sizeof buffer, file) 通常更容易理解與掌握。它最多讀取緩衝區容量減一個字元;若換行符號能放入緩衝區,也會一併保留。使用緩衝區前,請先檢查函式的回傳值。如果緩衝區已滿但尚未讀到換行符號,代表同一邏輯行仍有內容留在串流中;依照需求繼續讀取後續區塊,或丟棄剩餘部分。最後一行可能在沒有換行符號的情況下以 EOF 結束。fgets 也能自然處理空白行,因為它可能回傳只包含換行符號的緩衝區。
需要讀取格式化欄位或以空白分隔的詞元時,選擇 fscanf。需要保留行界線時,選擇 fgets,並視需要另外解析讀到的字串。務必檢查 fopen 是否成功、確認轉換結果,並在使用後關閉串流。