精华内容
下载资源
问答
  • 在之前文章《生信(五)awk求取某一平均值》中,笔者曾经给出过C语言求取某列平均值代码,但是最近回顾时发现,这段代码至少有几点不足: 利用 fgetc 函数来读取文件,现在看来效率不高。 如果文件最后没有...

    原创: hxj7

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

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

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

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

    大家都知道,C语言读取文件的常用函数有 fgetc、fgets、fread 以及 fscanf 等。笔者曾经一度以为就读取文件的效率而言,fgetc 不亚于其他函数。但是究竟是不是这样,还是自己验证一下让自己信服。
    首先随机生成一个文件,1000万行,4列(该文件下面还会用到)。我们看一下上述函数读取文件的效率:
    在这里插入图片描述
    从上图中可以看出,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 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列平均数的功能,它们的效率如下:

    在这里插入图片描述
    代码如下: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 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语言fgets函数按行读取文件

    千次阅读 2018-05-06 23:12:45
    Get a string from a stream.C语言没有像C++、Python语言的getline()函数,无法读取文件的某一行。然而,C语言有fgets()函数,该函数返回string类型,关键是该函数遇到换行符或EOF,则读取结束。利用这一特点,我们...

    fgets, fgetws
    Get a string from a stream.C语言没有像C++、Python语言的getline()函数,无法读取文件的某一行。然而,C语言有fgets()函数,该函数返回string类型,关键是该函数遇到换行符或EOF,则读取结束。利用这一特点,我们可以设置n为适当的缓冲区大小,即可以实现按行读取。

    char *fgets( char *string, int n, FILE *stream );
    wchar_t *fgetws( wchar_t *string, int n, FILE *stream );

    Function Required Header Compatibility 
    fgets <stdio.h> ANSI, Win 95, Win NT 
    fgetws <stdio.h> or <wchar.h> ANSI, Win 95, Win NT 

    For additional compatibility information, see Compatibility in the Introduction.

    Libraries


    LIBC.LIB Single thread static library, retail version 
    LIBCMT.LIB Multithread static library, retail version 
    MSVCRT.LIB Import library for MSVCRT.DLL, retail version 


    Return Value

    Each of these functions returns string. NULL is returned to indicate an error or an end-of-file condition. Use feof or ferror to determine whether an error occurred.


    Parameters

    string
    Storage location for data

    n
    Maximum number of characters to read

    stream
    Pointer to FILE structure

    Remarks

    The fgets function reads a string from the input stream argument and stores it in string. fgets reads characters from the current stream position to and including the first newline character, to the end of the stream, or until the number of characters read is equal to n – 1, whichever comes first. The result stored in string is appended with a null character. The newline character, if read, is included in the string. 

    fgets is similar to the gets function; however, gets replaces the newline character with NULL. fgetws is a wide-character version of fgets. 

    fgetws reads the wide-character argument string as a multibyte-character string or a wide-character string according to whether stream is opened in text mode or binary mode, respectively. For more information about using text and binary modes in Unicode and multibyte stream-I/O, see Text and Binary Mode File I/O and Unicode Stream I/O in Text and Binary Modes.

    e.g:

    #include "StaticLib.h"
    #include "stdio.h"
    #include "string.h" 
    
    bool fnShow()
    {
    	char cFileName[] = "..\\StaticLib\\StaticLib.h";
    	char cFind[] = "extern";
    	char cLine[1024];
    	int iBuff = 1024;
        FILE *fp;
    	fp = fopen(cFileName,"r");
    	if(NULL == fp)
    	{
    		printf("打开文件失败!\n");
    		return false;
    	}
    	while(!feof(fp))
    	{
    		fgets(cLine,iBuff,fp);
    		if(strstr(cLine,cFind))
    		{
    		    printf("%s",cLine);
    		}
    	}
    
    	fclose(fp);
    	return true;
    }



    展开全文
  • 操作配置文件的代码分.h,.c和main.c(示例) 每一行不超过1024字符。 1.注释以#打头,行首空格要忽略 2.一个参数占一行,配置项格式 变量名 = 变量值 变量名= (也合法. =两边有无空格不影响结果,值可以为空格) 3.没有...
  • 这个不能直接插入, 因为数据在文件中存储是顺序存储, 你插入数据会覆盖掉后面内容, ...以下代码实现将文件中第6行处插入一行, 即原来第6行以后依次往后移一行. #include int main(void) { FILE *fp;
    这个不能直接插入, 因为数据在文件中存储是顺序存储的, 你插入的数据会覆盖掉后面的内容, 只有把插入点位置后面的数据都读取出来存着, 然后在文件指针处插入你要写的数据, 最后将你保存的数据再写到文件, 才能实现真正的插入到文件.

    以下代码实现将文件中第6行处插入一行, 即原来的第6行以后依次往后移一行.

    #include <stdio.h>

    int main(void)
    {
    FILE *fp;
    int i;
    char buf[1024]; // 假设每行不超过1024字节, 根据情况调节大小

    if (!(fp = fopen("./a.txt", "r+"))) { // 尝试以读写方式打开文件.
    fprintf(stderr, "Open failed.\n");
    return 1;
    }

    for (i = 0; i < 5; i++) { // 循环5次, 读掉前5行
    fgets(buf, 1024, fp); // 读取一行
    }

    // 此时文件指针指向第6行行首
    long offset = ftell(fp); // 记录文件指针位置, 因为后面还要读, 文件指针会移走

    // 这里为了程序易懂, 假设后面不超过100行, 每行不超过1024字节, 否则需要用链表或二重 //指针的方式, 可以保证不浪费空间, 但代码就较复杂
    char save[100][1024];

    i = 0; // 清0, 记录后面共有多少行
    while ((fgets(save[i], 1024, fp))) { // 循环读取文件, 直到fgets返回NULL表示读完
    i++;
    }

    printf("请输入要插入的数据内容:");
    fgets(buf, 1024, stdin); // 接收键盘输入的内容

    // 由于读完文件后, 文件指针指向文件尾, 这里重新定位到之前保存的位置
    fseek(fp, offset, SEEK_SET);

    fputs(buf, fp); // 写要插入的数据

    int j;

    for (j = 0; j < i; j++) { // 之前保存的数据, 依次往后面写
    fputs(save[j], fp);
    }

    return 0;
    }
    展开全文
  • 从文本文件中逐行读取字符串,作为链表个节点数据。从键盘输入命令字符,可以对缓冲区buffer中文本进行定位,查找,替换,删除某行,添加某行等操作。编译环境VC6.0。fflush在VC6.0下可以正确工作,在其它编译...
  • 你必须知道495个C语言问题

    千次下载 热门讨论 2015-05-08 11:09:25
    1.24 我在文件中定义了个extern数组,然后在另文件中使用,为什么sizeof取不到数组大小? 声明问题 1.25 函数只定义了次,调用了次,但编译器提示非法重声明了。 *1.26 main正确定义是什么...
  • 《你必须知道495个C语言问题》

    热门讨论 2010-03-20 16:41:18
    1.24 我在文件中定义了个extern数组,然后在另文件中使用,为什么sizeof取不到数组大小? 13 声明问题 14 1.25 函数只定义了次,调用了次,但编译器提示非法重声明了。 14 *1.26 main正确...
  • // 将s所指向的某一块内存中的每个字节的内容全部设置为ch指定的ASCII值----转换为ascii之后方便计算?---- }//回79 } void showFileData(char ** pArray, int len)//以show为开头的函数,其意义因该为展示...
  • 1.24 我在文件中定义了个extern数组,然后在另文件中使用,为什么sizeof取不到数组大小? 13 声明问题 14 1.25 函数只定义了次,调用了次,但编译器提示非法重声明了。 14 *1.26 main正确...
  • 1.24 我在文件中定义了个extern数组,然后在另文件中使用,为什么sizeof取不到数组大小?  声明问题  1.25 函数只定义了次,调用了次,但编译器提示非法重声明了。  *1.26 main正确定义是...
  •  1.24 我在文件中定义了个extern数组,然后在另文件中使用,为什么sizeof取不到数组大小? 声明问题 1.25 函数只定义了次,调用了次,但编译器提示非法重声明了。 *1.26 main正确定义是...
  • [例10.2]从键盘输入一行字符,写入一个文件, 再把该文件内容读出显示在屏幕上。 #include main() { FILE *fp; char ch; if((fp=fopen("string","wt+"))==NULL) { printf("Cannot open file strike any key exit!");...
  • 今天看到了一个LINUX下有趣命令。 fortune命令。 当你执行此命令时,屏幕会随机显示一个格言。 ...然后,我花了一点时间用C语言做了...//读取文件某一行的格言 char * ReadSpeacialLine(int row,char filename[]) {

    今天看到了一个LINUX下的有趣命令。

    fortune命令。

    当你执行此命令时,屏幕会随机显示一个格言。


    然后,我花了一点时间用C语言做了一个大致的DEMO程序。


    C语言程序:

    #include<stdio.h>
    #include<stdlib.h>
    #include<time.h>
    
    //读取文件某一行的格言
    char * ReadSpeacialLine(int row,char filename[]) 
    { 
        FILE *fp; 
        int WhichLine=row;             //指定要读取哪一行
        int CurrentIndex=0;             //当前读取的行
        char StrLine[1024];             //每行最大读取的字符数,可根据实际情况扩大
        if((fp = fopen(filename,"r")) == NULL) //判断文件是否存在及可读
        { 
            printf("error!"); 
            return NULL; 
        } 
    
        while (!feof(fp)) 
        { 
    		
            if (CurrentIndex==WhichLine)
            {
                fgets(StrLine,1024,fp);  //读取一行
                printf("%s", StrLine); //输出
                return StrLine;
            }
            fgets(StrLine,1024,fp);  //读取一行,并定位到下一行
            CurrentIndex++;
        } 
        fclose(fp);                     //关闭文件
        return NULL; 
    }
    
    //计算文件的总行数(便于后面产生一定范围内的随机数)
    int SumOfRows(char filename[])
    {
    	FILE *fp;
    	int sum_rows=1,c;
    	fp=fopen(filename,"r"); 
    	if (fp!=NULL)
    	while ((c=fgetc(fp))!=EOF)
    	{ 
    		if(c=='\n')
    		sum_rows++;  
    	}
    	fclose(fp);
    	return sum_rows;
    }
    
    //产生在文件总行数以内的随机数
    int init_rand(char filename[])
    {
    	int	sum_rows=SumOfRows(filename);
    	int row;
    	int begin=0;
    	srand(time(NULL));  /*初始化随机数种子*/
    	row=rand()%(sum_rows-begin)+begin;  /*生成一个[t,sum_rows)区间内的整数*/
    	return row;
    }
    
    int main()
    {
    	char filename[] = "maxim.txt"; //文件名
    	int row=init_rand(filename);
    	ReadSpeacialLine(row,filename);
    	return 0;
    }
    


    我的格言集:



    第一次:

    第二次:


    第三次:


    展开全文
  • 你必须知道495个C语言问题(PDF)

    热门讨论 2009-09-15 10:25:47
    难道在C语言中一个结构不能包含指向自己指针吗? . . . . 3 1.7 怎样建立和理解非常复杂声明?例如定义个包含N 个指向返 回指向字符指针函数指针数组? . . . . . . . . . . . . . . 3 1.8 函数只定义...
  • 1.24 我在文件中定义了个extern数组,然后在另文件中使用,为什么sizeof取不到数组大小? 42 声明问题 43 1.25 函数只定义了次,调用了次,但编译器提示非法重声明了。 43 *1.26 main正确定义...
  • 1.24 我在文件中定义了个extern数组,然后在另文件中使用,为什么sizeof取不到数组大小? 42 声明问题 43 1.25 函数只定义了次,调用了次,但编译器提示非法重声明了。 43 *1.26 main正确定义...
  •  显示:可显示已有学生或课程信息,每条记录占据一行;  编辑:可根据查询结果对相应记录进行修改,修改时注意编号唯一性;  删除:对已有学生或课程记录进行删除。如果当前系统中没有相应记录,...
  • C实用经典函数集合,学习必看! 读键盘扫描码 获取机器日期 将浮点数转化为字符串 ...修改文件的某一行 成批拷贝文件 拷贝一个文件 建立目录 得到目录 得到文件名 任意两个正整数相加(位) 任意两个正整数相乘
  • 描述 请编程完成以下任务: ...首行包括区间数目n,1≤n≤10000,接下来n行,每行包括两个整数a,b,被一空格隔开,0≤a≤b≤10000,它们是某一个区间开始值和结束值。 输出格式 第一行集合元素个数,对于...
  • 难道在C语言中一个结构不能包含指向自己指针吗? o 2.7 怎样建立和理解非常复杂声明?例如定义个包含 N 个指向返回指向字符指针函数指针数组? o 2.8 函数只定义了次, 调用了次, 但编译器提示...
  • 将需要加密的一行文字输入加密程序,程序根据加密表中对应关系,可以简单地将输入文字加密输出,对于表中未出现字符则不加密。 运行示例: 输入:lajgdike,w 输出:ldjg,abice (12)编写程序验证以下说法:...
  •  本书目标是使你在C语言程序设计方面由位初学者成为位称职程序员。 内容简介  本书是编程语言先驱者Ivor Horton经典之作,是C语言方面最畅销图书品种之。本书集综合性、实用性为一体,是学习C语言...
  • 汽车站每天有n个发车班次,每个班次都有班次号(1、2、3…n),固定发车时间,固定路线(起始站、终点站),大致行车时间,固定...(5)读取功能:可将保存在文件信息读入到当前系统中,供用户进行使用。
  • 前几个月C语言结课,做了个数独游戏的大作业。因为不满足于命令行界面的简陋效果,就现...3. 选中数独图上的某一格,其、列、九宫格会加深颜色,以做提示。 解题代码 /* 使用solveSudoku算法解数独 */ int solveSud
  • 检测磁盘是否准备就绪 检测磁盘是否写保护 修改文件的某一行 成批拷贝文件 拷贝一个文件 建立目录 得到目录 得到文件名 任意两个正整数相加(位) 任意两个正整数相乘
  • 可以通过在函数中调入不同参数与设置使到个函数同时实现膨胀与腐蚀功能,而开与闭功能只需要连续调用两次函数,并且参数不同就了,使用非常简单。 然后就是软件使用部分,软件位置依然是放在Release...
  •  课程的数据文件的格式是怎样的?(数据文件由所教授课程的老师编辑操作而非程序员)  如何将数据文件使用的外部表示转换为内部表示?  如何编写程序对数据库进行操作? 三.问题的框架: 程序运行的基本操作...

空空如也

空空如也

1 2 3 4
收藏数 63
精华内容 25
关键字:

c语言读取文件的某一行

c语言 订阅