詳解C語(yǔ)言讀取文件求某一列的平均值
第一部分:比較讀取文件的效率
在之前的文章《生信(五)awk求取某一列的平均值》中,筆者曾經(jīng)給出過(guò)C語(yǔ)言求取某列平均值的代碼,但是最近回顧時(shí)發(fā)現(xiàn),這段代碼至少有幾點(diǎn)不足:
1. 利用 fgetc 函數(shù)來(lái)讀取文件,現(xiàn)在看來(lái)效率不高。
2. 如果文件最后沒(méi)有一個(gè)空白行的話,會(huì)陷入無(wú)限循環(huán)。也就是對(duì) EOF 的處理不完善。
大家都知道,C語(yǔ)言讀取文件的常用函數(shù)有 fgetc、fgets、fread 以及 fscanf 等。筆者曾經(jīng)一度以為就讀取文件的效率而言,fgetc 不亞于其他函數(shù)。但是究竟是不是這樣,還是自己驗(yàn)證一下讓自己信服。
首先隨機(jī)生成一個(gè)文件,1000萬(wàn)行,4列(該文件下面還會(huì)用到)。我們看一下上述函數(shù)讀取文件的效率:
從上圖中可以看出,fread 的效率最高,fgetc 的效率最低。當(dāng)然這種比較很粗淺,但是能大概看出趨勢(shì)。
各個(gè)函數(shù)讀取文件的代碼如下:其中 main 函數(shù)是一樣的,只是 readFile 函數(shù)的實(shí)現(xiàn)不同。
#include <stdio.h> #include <stdlib.h> #include <time.h> #define BUFSIZE 4096 void readFile(FILE* fp); int main(int argc, char* argv[]) { FILE *fp; time_t start, end; start = time(NULL); if (argc < 2) { printf("Usage: %s <filename>\n", argv[0]); return 1; } if ((fp = fopen(argv[1], "r")) == NULL) { printf("Error: cannot open file\n"); return 1; } readFile(fp); fclose(fp); end = time(NULL); printf("time spent: %d seconds\n", end - start); return 0; } // readFile_fgetc: void readFile(FILE* fp) { char c; while ((c = fgetc(fp)) != EOF) ; } // readFile_fgets: void readFile(FILE* fp) { char buf[BUFSIZE]; while (fgets(buf, MAXLINE, fp) != NULL) ; } // readFile_fread: void readFile(FILE* fp) { char buf[BUFSIZE]; while (fread(buf, 1, BUFSIZE, fp) > 0) ; } // readFile_fscanf: void readFile(FILE* fp) { char buf[BUFSIZE]; while (fscanf(fp, " %[^\n]s", buf) == 1) ; }
第二部分:比較求取列平均值的效率
那么各個(gè)函數(shù)計(jì)算列平均值的效率如何呢?我們依然使用上面那1000萬(wàn)行的文件,用上述各個(gè)函數(shù)實(shí)現(xiàn)計(jì)算第2列平均數(shù)的功能,它們的效率如下:
代碼如下:main 函數(shù)大體上是一樣的,只是 colAver 函數(shù)的實(shí)現(xiàn)不一樣。
(這些代碼完善地處理了EOF,無(wú)論文件最后是否有空白行都可以正確運(yùn)行。但是仍然有前提,就是文件中每一行的分隔符(列數(shù))是一樣的,否則代碼可能會(huì)出錯(cuò)。)
這些代碼中,fscanf 的最簡(jiǎn)短,該函數(shù)可以大大提高格式化讀取數(shù)據(jù)的編程效率。
#include <stdio.h> #include <stdlib.h> #include <time.h> #define BUFSIZE 4096 void getColAver(FILE* fp, const int k); int main(int argc, char* argv[]) { FILE *fp; time_t start, end; start = time(NULL); if (argc < 2) { printf("Usage: %s <filename>\n", argv[0]); return 1; } if ((fp = fopen(argv[1], "r")) == NULL) { printf("Error: cannot open file\n"); return 1; } getColAver(fp, 2); fclose(fp); end = time(NULL); printf("time spent: %d seconds\n", end - start); return 0; } // colAver_fgetc: void getColAver(FILE* fp, const int k) { int i = 0; // num of '\t' int j = 0; // num of chars int c; // char char col[50]; float sum = 0; int n = 0; // num of lines. int inCol = 0; while ((c = fgetc(fp)) != EOF) { if (i == k - 1) { inCol = 1; if (c == '\t') i++; else if (c == '\n') i = 0; else col[j++] = c; } else { if (c == '\t') i++; else if (c == '\n') i = 0; if (inCol) { col[j] = '\0'; sum += atof(col); n++; } j = 0; inCol = 0; } } if (inCol) { col[j] = '\0'; sum += atof(col); n++; } if (n == 0) printf("Error: no line!\n"); else printf("The average of col %d is %f\n", k, sum / n); } // colAver_fgets: void getColAver(FILE* fp, const int k) { int i = 0; // num of '\t' int j = 0; // num of chars char col[50]; char buf[BUFSIZE]; float sum = 0; int n = 0; // num of lines. int inCol = 0; char* p; while (fgets(buf, BUFSIZE, fp) != NULL) { for (p = buf; *p != '\0'; p++) { if (i == k - 1) { inCol = 1; if (*p == '\t') i++; else if (*p == '\n') i = 0; else col[j++] = *p; } else { if (*p == '\t') i++; else if (*p == '\n') i = 0; if (inCol) { col[j] = '\0'; sum += atof(col); n++; } j = 0; inCol = 0; } } } if (inCol) { col[j] = '\0'; sum += atof(col); n++; } if (n == 0) printf("Error: no line!\n"); else printf("The average of col %d is %f\n", k, sum / n); } // colAver_fread: void getColAver(FILE* fp, const int k) { int i = 0; // num of '\t' int j = 0; // num of chars char col[50]; char buf[BUFSIZE]; float sum = 0; int n = 0; // num of lines. int m, l; int sizeChr = sizeof(char); int inCol = 0; while ((l = fread(buf, sizeChr, BUFSIZE, fp)) > 0) { for (m = 0; m < l; m++) { if (i == k - 1) { inCol = 1; if (buf[m] == '\t') i++; else if (buf[m] == '\n') i = 0; else col[j++] = buf[m]; } else { if (buf[m] == '\t') i++; else if (buf[m] == '\n') i = 0; if (inCol) { col[j] = '\0'; sum += atof(col); n++; } j = 0; inCol = 0; } } } if (inCol) { col[j] = '\0'; sum += atof(col); n++; } if (n == 0) printf("Error: no line!\n"); else printf("The average of col %d is %f\n", k, sum / n); } // colAver_fscanf: void getColAver(FILE* fp) { float f; float sum = 0; int n = 0; // num of lines. while (fscanf(fp, "%*s%f%*[^\n]s", &f) == 1) { sum += f; n++; } if (n == 0) printf("Error: no line!\n"); else printf("The average of col 2 is %f\n", sum / n); }
以上就是詳解C語(yǔ)言讀取文件求某一列的平均值的詳細(xì)內(nèi)容,更多關(guān)于C語(yǔ)言讀取文件求某一列的平均值的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
C語(yǔ)言實(shí)現(xiàn)火車(chē)票管理系統(tǒng)
這篇文章主要為大家詳細(xì)介紹了C語(yǔ)言實(shí)現(xiàn)火車(chē)票管理系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-03-03C語(yǔ)言實(shí)現(xiàn)三子棋小游戲全程詳解
完成一個(gè)三子棋的代碼并不是很難,有困難且重要的是完成這個(gè)游戲代碼所具備的思想,因?yàn)樗枷肷系倪M(jìn)步才是真正的進(jìn)步,當(dāng)我們有了這個(gè)思想上的武器,寫(xiě)出別的代碼,難度就不會(huì)高2022-05-05基于C語(yǔ)言實(shí)現(xiàn)的aes256加密算法示例
這篇文章主要介紹了基于C語(yǔ)言實(shí)現(xiàn)的aes256加密算法,結(jié)合具體實(shí)例形式詳細(xì)分析了C語(yǔ)言實(shí)現(xiàn)的aes256加密算法實(shí)現(xiàn)步驟與使用技巧,需要的朋友可以參考下2017-02-02C++構(gòu)造函數(shù)和析構(gòu)函數(shù)的使用與講解
今天小編就為大家分享一篇關(guān)于C++構(gòu)造函數(shù)和析構(gòu)函數(shù)的使用與講解,小編覺(jué)得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來(lái)看看吧2018-12-12c語(yǔ)言與c++基礎(chǔ)知識(shí)點(diǎn)(必看)
下面小編就為大家?guī)?lái)一篇c語(yǔ)言與c++基礎(chǔ)知識(shí)點(diǎn)(必看)。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2016-07-07C++實(shí)現(xiàn)LeetCode(兩個(gè)有序數(shù)組的中位數(shù))
這篇文章主要介紹了C++實(shí)現(xiàn)LeetCode(兩個(gè)有序數(shù)組的中位數(shù)),本篇文章通過(guò)簡(jiǎn)要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下2021-07-07