Re: [問題] 如何知道一個檔案有幾行
※ 引述《CS1DADA (CS1DADA)》之銘言:
: 小弟目前想到的是使用fgetchar()
: 計算一個file中有多少個'\n',
: 根據'\n'的個數有多少來算行數
: 不知道有沒有更快或是不同的想法呢?
: 謝謝
既然推文中也有人開始注意,
由於小弟之前處理檔案都不算小,對於讀取速度上小有研究,
放上一些過程和數據,目前想到比 fgets 快、穩的方法在 step 4
皆為 C 可使用之函式庫,說明有些冗長,請多包涵;有誤請不吝指正。
--------
step1 : 產生測試資料
(1) 固定產生一 LINE_CNT 行之檔案
(2) 第 i 行之字元數,限定為 100~2000 字元,以 rand 決定
(3) 每個字元產生方式: rand() % 26 + 'a'
程式碼大概長這樣
int i, j, k;
FILE *fp=fopen(FILENAME, "w");
srand(0); // 不同電腦、相同compiler產生結果一樣
for(i=0; i!=LINE_CNT; ++i){ // 產生 LINE_CNT 行
j = rand() % 1901 + 100; // 第 i 行產生 j 個 a~z, j: [100, 2000]
for(k=0; k!=j; ++k) fputc(rand()%26 + 'a', fp);
fputc('\n', fp);
}
fclose(fp);
※ 實際設 LINE_CNT = 200 萬, 產生大小約 1.93 GB
--------
step2 : 以 fgetc 進行
char ch;
int line_cnt=0;
FILE *fp=fopen(FILENAME, "r");
t1=clock();
while( ( ch = fgetc(fp)) != EOF) if(ch=='\n') ++line_cnt;
t2=clock();
fclose(fp);
※ 這是最慢的方式,非常不建議這麼做
---------
step 3: 以 fgets 進行
int line_cnt=0;
char buf[BUF_SIZE+1]={0};
FILE *fp=fopen(FILENAME, "r");
t1=clock();
while(fgets(buf, BUF_SIZE, fp)!=NULL) ++line_cnt;
t2=clock();
fclose(fp);
※ 事實上這段碼有「極小」可能會出包,該檔案若有幾行特別特別長的話,
※ 便不能確信 fgets 能一次抓完一行, 最保險是抓完後再去判斷 buf[len-1]='\n'
※ 但用到 brach 感覺就不好了
----------
step 4: 用 fread 進行
t1=clock();
while(BUF_SIZE==fread(buf, 1, BUF_SIZE, fp)){
ptr = (char*)strchr(buf, '\n');
while(ptr!=NULL){
++line_cnt;
ptr = (char*)strchr(ptr+1, '\n');
}
}
t2=clock();
※ 用 fread 比 fgets 好的地方在於,每次必抓 BUF_SIZE 這麼多字,
※ 若每行只有十幾二十個字,用 fgets 還是要分很多次抓取
-----------
Result :
VS2008, 開 O2,
fgetc:143.953 secs
fgets:106.406 secs
* fread: 47.718 secs
檔案讀取之速度原則大致上應有二點要注意:
(a) 能減少讀檔次數就盡量減少, 將動作放到 memory 裡進行
(b) 注意有些函式做 parse 速度非常慢
------------
以上, 供參考.
--
YouLoveMe() ? LetItBe() : LetMeFree();
--
※ 發信站: 批踢踢實業坊(ptt.cc)
◆ From: 180.177.73.222
→
06/10 19:29, , 1F
06/10 19:29, 1F
→
06/10 19:40, , 2F
06/10 19:40, 2F
→
06/10 19:41, , 3F
06/10 19:41, 3F
→
06/10 19:43, , 4F
06/10 19:43, 4F
→
06/10 20:12, , 5F
06/10 20:12, 5F
→
06/10 20:13, , 6F
06/10 20:13, 6F
→
06/10 21:47, , 7F
06/10 21:47, 7F
→
06/10 21:48, , 8F
06/10 21:48, 8F
→
06/11 05:04, , 9F
06/11 05:04, 9F
→
06/11 05:05, , 10F
06/11 05:05, 10F
→
06/11 05:06, , 11F
06/11 05:06, 11F
討論串 (同標題文章)