c fscanf 按行读取文件_C语言读取文件(一)——再谈如何求某一列的平均值

de0f1ad8882c9a304a977199c11e7844.png

原创:hxj7

本文粗浅比较了C语言中常用的几种读取文件的函数的效率,并给出了几段求取某列平均值的代码。

第一部分:比较读取文件的效率


在之前的文章a href="http://mp.weixin.qq.com/s?__biz=MzU0Nzk1NzcwMA==&mid=2247483910&idx=1&sn=c300630178addb098a2702215fb7785a&chksm=fb473cadcc30b5bb67df16cbdc70a5015af3147a17d3780b45f10b5336c0c0fda20ce91775d6&scene=21#wechat_redirect">《生信(五)awk求取某一列的平均值》中,笔者曾经给出过C语言求取某列平均值的代码,但是最近回顾时发现,这段代码至少有几点不足

  1. 利用 fgetc 函数来读取文件,现在看来效率不高。
  2. 如果文件最后没有一个空白行的话,会陷入无限循环。也就是对 EOF 的处理不完善。

大家都知道,C语言读取文件的常用函数fgetcfgetsfread 以及 fscanf 等。笔者曾经一度以为就读取文件的效率而言,fgetc 不亚于其他函数。但是究竟是不是这样,还是自己验证一下让自己信服。
首先随机生成一个文件,1000万行4列(该文件下面还会用到)。我们看一下上述函数读取文件的效率:

171298f6c2ec8065446f7584a0a7f951.png

从上图中可以看出,fread 的效率最高,fgetc 的效率最低。当然这种比较很粗浅,但是能大概看出趋势。
各个函数读取文件的代码如下:其中 main 函数是一样的,只是 readFile 函数的实现不同。

#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 filen");
 return 1;
  }
  readFile(fp);
  fclose(fp);
  end = time(NULL);
 printf("time spent: %d secondsn", 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)
    ;
}

第二部分:比较求取列平均值的效率

那么各个函数计算列平均值的效率如何呢?我们依然使用上面那1000万行的文件,用上述各个函数实现计算第2列平均数的功能,它们的效率如下:

b87cd8a170e93baafd5aed88296e63f3.png


代码如下:main 函数大体上是一样的,只是 colAver 函数的实现不一样。
(这些代码完善地处理了EOF,无论文件最后是否有空白行都可以正确运行。但是仍然有前提,就是文件中每一行的分隔符(列数)是一样的,否则代码可能会出错。)
这些代码中,fscanf 最简短,该函数可以大大提高格式化读取数据的编程效率

#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 filen");
 return 1;
  }
  getColAver(fp, 2);
  fclose(fp);
  end = time(NULL);
 printf("time spent: %d secondsn", 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 %fn", 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 %fn", 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 %fn", 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 %fn", sum / n);
}

(公众号:生信了)

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值