fseek 先移至末尾取大小,再移至開頭統計行數int lines() {
FILE *fp;
int line = 0, filesize = 0;
char ch = 0;
if ((fp = fopen("c:\\filename.txt", "r")) == NULL)
fp = fopen("c:\\filename.txt", "w"); // 若不存在則建立空檔
fseek(fp, 0, SEEK_END); // ① 移至檔案末尾
filesize = ftell(fp); // ② 取得檔案總位元組數
fseek(fp, 0, SEEK_SET); // ③ 移回檔案開頭
while (filesize--) { // ④ 逐字元讀取計算行數
ch = fgetc(fp);
if (ch == 0x0A) ++line; // 0x0A = '\n' (LF)
}
fclose(fp);
return line;
}
fseek 的用意| 步驟 | 呼叫 | 目的 |
|---|---|---|
| ① | fseek(fp, 0, SEEK_END) | 將檔案指標定位到**檔案結尾**,為 ftell 取得總大小做準備 |
| ② | filesize = ftell(fp) | 回傳檔案指標距離檔案開頭的**位元組偏移量**,即檔案大小 |
| ③ | fseek(fp, 0, SEEK_SET) | 將檔案指標**重置到檔案開頭**,以便後續 fgetc 從頭讀取每個字元 |
| ④ | while(filesize--) + fgetc | 利用已知大小作為迴圈計數器,逐字元掃描統計 '\n'(行數) |
SEEK_SET (0) = 從檔案開頭偏移,SEEK_CUR (1) = 從當前位置偏移,SEEK_END (2) = 從檔案結尾偏移。ftell 回傳 long,大檔案(>2GB)需用 ftello64 / _ftelli64。fgetc 回傳 int(含 EOF),賦值給 char 會截斷 EOF(-1),建議用 int ch 接收並判斷 ch != EOF。\r\n (0x0D 0x0A),純文本模式 fopen(..., "r") 會自動轉換為單一 \n,故只檢查 0x0A 即可。二進位模式 "rb" 需自行處理 \r\n。int count_lines(const char *path) {
FILE *fp = fopen(path, "r");
if (!fp) return -1;
int lines = 0;
int ch;
while ((ch = fgetc(fp)) != EOF) {
if (ch == '\n') ++lines;
}
fclose(fp);
return lines;
}
優點:不需 fseek/ftell、支援任意大小檔案、文本模式自動處理換行符、碼更簡潔。
原代碼雙 fseek 是為了**先取得檔案大小作為迴圈計數器**,再從頭掃描。現代寫法直接用 fgetc 迴圈至 EOF 更簡單、安全、無大小限制。