作者tropical72 (蓝影)
看板C_and_CPP
标题Re: [问题] 如何知道一个档案有几行
时间Fri Jun 10 17:24:25 2011
※ 引述《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
1F:→ firejox:假如你有unistd.h 就可以用read() XD 06/10 19:29
2F:→ adxis:用 fopen 得到的 FILE* 原本就配有 buffer 大小是 BUF_SIZ 06/10 19:40
3F:→ adxis:直接把那个 buffer 配大一点就能加速了 也不用自己管 06/10 19:41
4F:→ adxis:有格式化需求才考虑自己管 不然会多花一次 memcpy 06/10 19:43
5F:→ tropical72:试问adxis,照您的说法,该如何撰之?恳请赐教. 06/10 20:12
6F:→ tropical72:@firejox,确实低阶之write/read应会再快些. 06/10 20:13
7F:→ angleevil:以c来讲的话,第四个方法最好.毕竟unistd.h无法跨平台 06/10 21:47
8F:→ angleevil:而且讲实话,当初我是用弟三个去算的,还真的没想到4 06/10 21:48
9F:→ adxis:t桑写法基本上只差系统buffer 那边没有利用到了 06/11 05:04
10F:→ adxis:之前回原原po文有回 只是没有写完整code 06/11 05:05
11F:→ adxis:至於memcpy 这边是我讲错了 见谅 06/11 05:06