服务器之家:专注于VPS、云服务器配置技术及软件下载分享
分类导航

PHP教程|ASP.NET教程|Java教程|ASP教程|编程技术|正则表达式|C/C++|IOS|C#|Swift|Android|VB|R语言|JavaScript|易语言|vb.net|

服务器之家 - 编程语言 - C/C++ - 详解C语言读取文件求某一列的平均值

详解C语言读取文件求某一列的平均值

2022-09-22 16:17hxj7 C/C++

本文粗浅比较了C语言中常用的几种读取文件的函数的效率,并给出了几段求取某列平均值的代码,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多度进步

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

在之前的文章《生信(五)awk求取某一列的平均值》中,笔者曾经给出过C语言求取某列平均值的代码,但是最近回顾时发现,这段代码至少有几点不足:

1. 利用 fgetc 函数来读取文件,现在看来效率不高。

2. 如果文件最后没有一个空白行的话,会陷入无限循环。也就是对 EOF 的处理不完善。

大家都知道,C语言读取文件的常用函数有 fgetc、fgets、fread 以及 fscanf 等。笔者曾经一度以为就读取文件的效率而言,fgetc 不亚于其他函数。但是究竟是不是这样,还是自己验证一下让自己信服。

首先随机生成一个文件,1000万行,4列(该文件下面还会用到)。我们看一下上述函数读取文件的效率:

详解C语言读取文件求某一列的平均值

从上图中可以看出,fread 的效率最高,fgetc 的效率最低。当然这种比较很粗浅,但是能大概看出趋势。

各个函数读取文件的代码如下:其中 main 函数是一样的,只是 readFile 函数的实现不同。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
#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)
    ;
}

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

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

详解C语言读取文件求某一列的平均值


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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
#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语言读取文件求某一列的平均值的详细内容,更多关于C语言读取文件求某一列的平均值的资料请关注服务器之家其它相关文章!

原文链接:https://blog.csdn.net/biocity/article/details/91895624

延伸 · 阅读

精彩推荐
  • C/C++C++基于栈的深搜算法实现马踏棋盘

    C++基于栈的深搜算法实现马踏棋盘

    这篇文章主要为大家详细介绍了C++基于栈的深搜算法实现马踏棋盘,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...

    coder_vivid4802022-09-22
  • C/C++C++程序中使用Windows系统Native Wifi API的基本教程

    C++程序中使用Windows系统Native Wifi API的基本教程

    这篇文章主要介绍了C++程序中使用Windows系统Native Wifi API的基本教程,包括在程序中控制无线网卡开关的方法,需要的朋友可以参考下...

    全速前行11512021-03-29
  • C/C++C 语言中实现环形缓冲区

    C 语言中实现环形缓冲区

    本文主要是介绍 C语言实现环形缓冲区,并附有详细实现代码,具有一定的参考价值,希望能帮助有需要的小伙伴...

    C语言教程网4272021-04-09
  • C/C++一文弄懂C语言如何实现单链表

    一文弄懂C语言如何实现单链表

    单链表是由多个结点链接组成,它的每个结点包含两个域,一个数据域和一个链接域(地址域),下面这篇文章主要给大家介绍了关于C语言如何实现单链表的相关...

    忱叁6232021-12-30
  • C/C++cocos2dx实现刮奖效果

    cocos2dx实现刮奖效果

    这篇文章主要为大家详细介绍了cocos2dx实现刮奖效果,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...

    Sun___Shine6202021-07-14
  • C/C++C++ new/delete相关知识点详细解析

    C++ new/delete相关知识点详细解析

    C语言用一堆标准库函数malloc和free在自由存储区中分配存储空间,而C++则用new和delete表达式实现相同的功能...

    C++教程网8882020-12-25
  • C/C++C语言编程之扫雷小游戏空白展开算法优化

    C语言编程之扫雷小游戏空白展开算法优化

    扫雷是电脑上很经典的游戏,特意去网上玩了一会,几次调试之后,发现这个比三子棋要复杂一些,尤其是空白展开算法上和堵截玩家有的一拼,与实际游...

    Booksort8962022-01-07
  • C/C++如何使用递归和非递归方式反转单向链表

    如何使用递归和非递归方式反转单向链表

    以下是对使用递归和非递归方式反转单向链表的示例进行了详细的分析介绍,需要的朋友可以过来参考下...

    C语言教程网2842020-12-18