Re: [問題] 如何知道一個檔案有幾行
原文在這 #1DyUBD7Q (C_and_CPP)
http://www.ptt.cc/bbs/C_and_CPP/M.1307697869.A.1DA.html
都翻起舊文了,給個機會,澄清一下。
我先自首件事,這篇文當初我只有小提 fread + strchr 可以達成
較穩定的需求,會這麼說是有個專案 BUF_SIZE 設 32767 , 結果
fgets 檔案有一行真的 overflow。
我必須強調,當初講的 fgets / fread + strchr / fgetc 等方式,
其實都沒考慮到檔案編碼、多國語系問題,然後 fread + strchr 只
是小提一下,當時實作上是順手寫的,這次將它完善。
※ 引述《gary8520 (元丁)》之銘言:
: 小弟學C不久,非資工人,
: 正在寫一個小程式需要讀數十行,每行字元十個左右的資料。
: 想瞭解BUF_size大約要怎麼取,
: 小小測試了一下,
: 我使用動態記憶體配製決定BUF_SIZE的大小(用for迴圈跑),
: 並算出line_cut。
: ※ 引述《tropical72 (藍影)》之銘言:
<............恕刪............>
: : ----------
: : step 4: 用 fread 進行
: 計算結果輸出為line_cnt4
: 這似乎就要看BUF_SIZE的大小…
<............恕刪............>
: 只要bufsize一改,這個方法算出來的結果就會不同?
: 說實在話我不知道為什麼,也想不出來為什麼"Orz
: 所以,若要像我讀小筆資料,step3的方法似乎是比較適當的。
^^^^^^^^^^^^ 就是 fgets
一般而言,不論檔案大小,大多做法都是用 fgets 去做,因很少有機會會遇到
存文字檔,一行很長的(正確的說,很少情況會遇到純文字檔會寫很大的,寫大
的話到後來都是用 binary mode 寫入),所以 buf_size 設大一點就沒事了,
一般我是直接給 BUFSIZ * 4 ,我手邊 compiler BUFSIZ 是給 512 。
---------------------
原 source code 有問題的 重點如下
while(BUF_SIZE==fread(buf, 1, BUF_SIZE, fp)){
ptr = (char*)strchr(buf, '\n');
/* 這裡還有個 issue 要修正 */
while(ptr!=NULL){
++line_cnt;
ptr = (char*)strchr(ptr+1, '\n');
}
}
關鍵其實在於 fread 傳回值 ,代表成功從檔案讀取了幾個 bytes ,
原本是只考慮成功讀取了 BUF_SIZE bytes 時才繼續往下做 , 想一下
如果檔案有 351 bytes, 每次讀 100 bytes , 最後會有 51 bytes 會
被丟掉,所以判斷式不該那麼下 [Lemma],要簡單的話是只要 fread
傳回值是非 0 就直接往下做。
然後考慮一下最後一次 fread 的情況,假設 BUF_SIZE = 100 , 但只讀
了 51 bytes , 這時候 buf 後面的 49 bytes 都不會被清 0 , 意思是說
如果 buf 後 49 bytes 裡面有 '\n' 的話就會被重覆計算, 所以在做
string search 之前要再塞個結束字元。
整個可以 run 的 code 如下。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
enum {LINE_CNT = 150, BUF_SIZE = 20};
const char * FILENAME = "tst.txt";
int main()
{
FILE * fp ;
char * ptr;
char buf[BUF_SIZE+1] ; // +1 : 加上結束字元
size_t read_bytes , line_cnt = 0;
fp = fopen(FILENAME, "rb"); // no error defect
while(read_bytes = fread(buf, 1, BUF_SIZE, fp)) { // read_bytes==0 時結束
buf[read_bytes] = '\0';
ptr = (char*)strchr(buf, '\n');
while(ptr!=NULL) {
++line_cnt;
ptr = (char*)strchr(ptr+1, '\n');
}
}
fclose(fp);
printf("line_cnt = %d\n", line_cnt);
return 0;
}
然後整個 fread + strchr , 其實可用 fread + memchr 做 , memchr 速度應會比
strchr 還快一點點 , 這裡就不再示範。
[Lemma]
當初之所以會用 while(BUF_SIZE==fread(buf, 1, BUF_SIZE, fp)) ,
是因為不想在 while loop 裡面做很多事,想單純化,最後沒讀滿 BUF_SIZE
的是跳出 loop 之後再獨立做,速度估會較快。
--
~ 這輩子與神手無緣
我只好當神獸了 ~
卡卡獸
--
※ 發信站: 批踢踢實業坊(ptt.cc)
◆ From: 180.177.74.188
→
02/02 20:20, , 1F
02/02 20:20, 1F
→
02/02 20:23, , 2F
02/02 20:23, 2F
→
02/02 20:48, , 3F
02/02 20:48, 3F
→
02/02 20:49, , 4F
02/02 20:49, 4F
→
02/02 20:57, , 5F
02/02 20:57, 5F
→
02/02 20:59, , 6F
02/02 20:59, 6F
→
02/02 21:01, , 7F
02/02 21:01, 7F
→
02/02 21:01, , 8F
02/02 21:01, 8F
推
02/02 21:12, , 9F
02/02 21:12, 9F
→
02/02 21:14, , 10F
02/02 21:14, 10F
→
02/02 21:14, , 11F
02/02 21:14, 11F
推
02/02 21:18, , 12F
02/02 21:18, 12F
→
02/02 21:18, , 13F
02/02 21:18, 13F
→
02/02 21:21, , 14F
02/02 21:21, 14F
→
02/02 21:25, , 15F
02/02 21:25, 15F
→
02/02 22:14, , 16F
02/02 22:14, 16F
→
02/02 22:18, , 17F
02/02 22:18, 17F
→
02/02 22:43, , 18F
02/02 22:43, 18F
→
02/02 22:45, , 19F
02/02 22:45, 19F
→
02/02 22:51, , 20F
02/02 22:51, 20F
→
02/02 22:52, , 21F
02/02 22:52, 21F
討論串 (同標題文章)
完整討論串 (本文為第 4 之 4 篇):
問題
0
12