ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

(十五)文件 -- 4. 面向行的I/O

2021-05-23 10:04:57  阅读:271  来源: 互联网

标签:读入 -- buffer 十五 缓冲区 fgets MaxLine infile 面向


4. 面向行的I/O

由于文件通常被划分成行,因此很有必要一次读入整行数据。

stdio.h中执行这一操作的函数为fgets,其函数原型为:

string fgets(char buffer[], int bufsize, FILE *infile);

此函数的作用在于将下一行文件读入字符数组buffer中。

通常,fgets在读入第一个换行字符后停止读取,但如果该行的长度超过了由函数参数bufsize限定的长度,则fgets函数将提前返回。

因此,buffer数组中表示终止的空字符前应为一换行符,除非该行文件过长,超出buffer的限制。


无论fgets读入的是一整行还是此行的一部分,通常情况下都会返回一个指针,指向函数中的第一个参数(即字符数组buffer)。

如果fgets在文件的末尾调用,则返回NULL


相应的输出函数为fputs,其函数原型为

void fputs(string str, FILE *outfile);

调用函数fputs可将字符从一个字符串复制到输出文件,直至达到该字符串的末尾为止。


可以利用fgetsfputs来实现 上一节 中介绍的函数CopyFile,该程序如下所示:

static void CopyFile(FILE *infile, FILE *outfile) {
    char buffer[MaxLine];
    while (fgets(buffer, MaxLine, infile)!=NULL) {
        fputs(buffer, outfile);
    }
}

当使用函数fgets时,必须为输入行提供一个缓冲区。

CopyFile这个例子中,数组的空间是由声明

char buffer[MaxLine];

在当前帧中显式分配的。

需要注意的是,此缓冲区的内存空间将在函数返回时释放。

如果想要将行中的字符更长久地存储起来,需将它们存储在函数调用结束后仍然存在的内存空间中。
通常来说,从堆中动态分配内存是一种更简便的方法。


如果对多次fgets调用使用同一个临时缓冲区,则需要为之分配新的内存空间。

仅有赋值是不够的。例如,下面的代码从一个输入文件中读入两行数据,并将它们存储在字符串变量line1line2中:

void ReadTwoLines(FILE *infile) {
    char buffer[MaxLine];
    string line1, line2;
    fgets(buffer, MaxLine, infile);
    line1 = buffer;
    fgets(buffer, MaxLine, infile);
    line2 = buffer;
}

上述代码使得line1line2的内容相同,出现这样的问题是因为,变量buffer虽然在概念上是一个字符串,在内存中占有特定的空间,但赋值语句:

line1=buffer;

仅仅将buffer的地址赋给了变量line1

当程序继续执行,要重新利用这块空间读入第二行文件时,同一块空间就用来存放第二个字符串了。

这样变量line1line2最终指向了相同的内存,因此两者的值是相同的字符串。


常见错误:

如果使用同一个字符缓冲区从同一个文件中读入多行,要记住在读入下一行数据之前,需要将数据从缓冲区中复制到其他存储空间。

如果不进行这样的操作,前一行的内容将被覆盖。


解决这个问题的办法之一是利用strlib库中的函数CopyString将每一个字符串写入各自的堆内存中,如下所示:

void ReadTwoLines(FILE *infile) {
    char buffer[MaxLine];
    string line1, line2;
    fgets(buffer, MaxLine, infile);
    line1 = CopyString(buffer);
    fgets(buffer, MaxLine, infile);
    line2 = CopyString(buffer);
}

另外一个解决方案就是利用在simpio.h中定义的函数ReadLine,它可以避免与fgets相关的其他问题:

  • 难以确定缓冲区的大小。有些文件中的行比较长,因此很难选择一个适合所有文件的缓冲区的大小。
  • 难以判断是否超出了缓冲区的界限。如果在调用函数fgets的过程中给定一个最大值,则意味着数据不会被写到所分配的缓冲区之外,但同样需要知道fgets是否读入了一个完整的行。使用fgets时的唯一做法是浏览缓冲区内的所有字符,检测是否包括换行符。
  • fgets存储换行符通常也会引起麻烦。在大多数的程序中,换行符只是一行结束的标记,而并不真正是数据的一部分。使用fgets意味着还需采取其他的步骤将缓冲区中的换行符删除。

fgets相比,ReadLine具有以下优点:

  • ReadLine在需要时自动分配堆内存,使得缓冲区不可能溢出。
  • ReadLine删除了标记每一行结束的换行符,所返回的数据只包括这一行中的字符。
  • ReadLine返回的每一个字符串都保存在各自的内存中,因此在存储一个字符串之前不必考虑是否需要进行复制。

函数ReadLine在遇到文件结束符时返回NULL





参考

《C语言的科学和艺术》 —— 15 文件

标签:读入,--,buffer,十五,缓冲区,fgets,MaxLine,infile,面向
来源: https://blog.csdn.net/m0_38111466/article/details/117063108

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有