在21世纪的我用C语言探寻世界本质 ——(文件操纵2)文件缓冲区和随机读取
https://i-blog.csdnimg.cn/direct/901219b393b2435b8abb58a400b4a906.png#pic_center人无完人,持之以恒,方能见真我!!!
共同进步!!
一、文件的随机读取函数
在上一篇的文章中,我们讲到了文件次序读取的各种函数,次序读取也就是从开头读到末端,没有选择,我们今天要讲的就是文件的随机读取
也就是我们不必按照文件的次序举行读写,可以通过一些函数更改读写的位置,从而实现我们所说的随机读写,接下来我们就来学习这些函数
1.fseek函数
fseek函数用来定位文件内容的光标,光标默认在开头,假如读取了一个字符,那么光标就会往背面移动一位,而fseek函数可以通过偏移量来定位光标,然后我们就可以从定位的位置举行读写,我们来看看fseek的原型:
int fseek ( FILE * stream, long int offset, int origin );
假如函数定位成功,那么就会返回0,定位失败就会返回一个非0值
它的第一个参数是我们要定位光标的流,第二个参数就是我们的偏移量,是一个长整型,它要根据我们的第三个参数来定,第三个参数origin可以是三个常量值,如下图:
https://i-blog.csdnimg.cn/direct/72bd2debcdf44c5c9043369cd2769fa5.png
当它取SEEK_SET时表示,光标的偏移量要从文件开头开始计算,当它取SEEK_CUR时,光标的偏移量要从当前光标位置开始计算,当取SEEK_END时,光标的偏移量要从文件尾开始计算,我们来举一个例子说明:
假设有一个文件中存储着abcde,现在光标的位置在a背面,如:
a | bcde
我们想要获取字符d,那么就要把光标移动到d的前面,如下:
abc | de
那么这时我们就要计算偏移量,偏移量是针对第三个参数origin的不同取值的,当origin取SEEK_SET时,我们光标的偏移量要从文件开头开始计算,那么此时我们要把光标移动到d前面,偏移量就是3
当origin取SEEK_CUR时,光标的偏移量就要从当前光标位置开始计算,那么此时我们要把光标移动到d前面,偏移量就是2
当origin取SEEK_END时,光标的偏移量要从文件尾开始计算,那么此时我们要把光标移动到d前面,
偏移量就是-2
以是偏移量不是绝对的,要看fseek第三个参数的取值
接下来我们就来看一段代码,实验分析代码运行的结果:
#include <stdio.h>
int main()
{
FILE* pf = fopen("test.txt", "w");
if (pf == NULL)
{
perror("fopen");
return 1;
}
fputs("This is an apple.", pf);
fseek(pf, 9, SEEK_SET);
fputs(" orange", pf);
fclose(pf);
pf = NULL;
return 0;
}
这个代码对文件里的光标位置做了更改,它的寄义就是将光标移动到从文件开头计算,偏移量为9的位置,我们颠末计算,应该在以下这个位置:
This is a|n apple.
我们来运行一下这个代码,看看看看结果
https://i-blog.csdnimg.cn/direct/b8583e8f2bab4ef18e86b483ea6baac3.png
但是我们还是有一些疑问,我们岂非每一次都去数偏移量吗?有没有什么办法可以计算偏移量呢?就要看我们接下来要学习的函数:ftell了
2.ftell函数
ftell函数的作用就是返回当前文件光标到文件开头的偏移量,我们来看看它的原型:
long int ftell ( FILE * stream );
它的原型看起来也很好理解,参数就是我们要操纵的流,返回值是长整型,返回的就是当前文件光标到文件开头的偏移量
接下来我们直接来看例子,看看代码运行会发生什么:
当前目录下有一个test.txt文件,内里的内容是hello world!
#include <stdio.h>
int main()
{
long size;
FILE* pf = fopen("test.txt", "r");
if (pf == NULL)
{
perror("fopen");
return 1;
}
fseek(pf, 0, SEEK_END);
size = ftell(pf);
fclose(pf);
printf("Size of test.txt: %ld bytes.\n", size);
pf = NULL;
return 0;
}
起首步伐打开了文件test.txt,创建了一个长整型变量size,随后利用了fseek函数,我们要看得懂这句代码是什么意思,它的意思就是,将文件光标移动到离文件末端偏移量为0的地方,现实上就是把光标移动到了文件末尾
然后此时我们利用ftell函数算出文件开头到光标的偏移量,也就是文件开头到文件末尾的偏移量,那么算出来的将会是我们字符的个数,而一个字符占用一个字节,以是我们就间接算出来了文件内容的大小
https://i-blog.csdnimg.cn/direct/f96f210ce6fd455582ed235e068c275e.png
3.rewind函数
rewind函数的作用就比较简朴了,就是把文件中的指针位置重置到文件开头,我们来看看它的原型:
void rewind ( FILE * stream );
它的参数就是我们要操纵的流,没有返回值,从原型看就可以发现它应该是一个很简朴的函数,它的作用就是将文件光标移动到开头,然后我们可以重新在开头对文件举行读写
#include <stdio.h>
int main()
{
int i;
char buffer;
FILE* pf = fopen("test.txt", "w+");
if (pf == NULL)
{
perror("fopen");
return 1;
}
for (i = 'A'; i <= 'Z'; i++)
{
fputc(n, pf);
}
rewind(pf);
fread(buffer, 1, 26, pf);
fclose(pf);
pf = NULL;
buffer = '\0';
printf(buffer);
return 0;
}
起首,步伐以读写的方式打开了当前目录下的test.txt文件,然后将大写字母A到Z的字符写入到了我们的test.txt文件中,随后就到了我们的rewind函数,它直接就将我们的光标移动到了开头
然后我们就又利用了fread函数将pf中的数据读了出来,然后关闭文件,打印了读出的数据
现在唯一的问题是,我们之前讲的fread是对二进制文件举行操纵,那么它能不能对平凡文本文件举行操纵呢?我们来看看代码的运行结果:
https://i-blog.csdnimg.cn/direct/9f98a82e170049ae880226d1a5ba92f3.png
可以看到代码成功把文件中的内容读出来了,说明fread既可以读取二进制文件和文本文件,我们可以在cplusplus.com这个链接下搜索这个函数,看看这个函数是如何表明的:
https://i-blog.csdnimg.cn/direct/5c48d04951934a60b034dc0933e212ab.png
可以看到fread是一个函数,它的原型我们也表明过,这里不多说了,我们可以看下一行加粗的字体,翻译过来就是,从流中读取数据块,看到这个表明我们就知道了,它读取时不是 只能读取二进制,而是可以读取数据块
以是在传参时我们才要传元素个数和元素大小,而读取数据块就不会分它是文本文件还是二进制文件,函数也没有明确说只能读取二进制文件,只是它可以读取二进制文件而已它写入的时间也是按照数据块举行写入
而另一个函数fwrite和函数fread也是一样的,它既可以写入文本数据又可以写入二进制数据,因为它写入的时间也是按照数据块举行写入
二、文件读取竣事的判断
1.被错误利用的feof
牢记:在⽂件读取过程中,不能⽤feof函数的返回值直接来判断⽂件的读取是否竣事,feof 的作⽤是:当⽂件读取竣事的时间,判断是读取竣事的缘故原由是否是:遇到⽂件尾竣事
再普通一点的说,feof利用的前提就是文件的读取已经竣事了,它的作用就是在文件读取竣事后判断文件是不是读到末尾竣事,假如我们用它去判断文件读取是否竣事,很显着是错误的
2.判断文件读取竣事的方法
以是我们对不同的文件,提供了不同的判断方法,如下:
(1)文本文件是否读取竣事
根据我们的读取函数的返回值来确定,在上一篇文章中我们就学过了文件读取函数,这里我们就不再多赘述
[*]判断函数fgetc的返回值是否为EOF
[*]判断函数fgets的返回值是否为NULL
(2)二进制文件是否读取竣事
[*]fread判断返回值是否⼩于现实要读的个数
3.判断文件竣事的缘故原由
刚刚我们学习了如何判断文件读取竣事,那么文件读取竣事了不一定就是正常的全部读取成功了,以是又会有正常读取竣事和错误读取
那么我们怎么判断文件是正常读取竣事还是错误读取竣事了呢?一样平常是利用feof函数和ferror函数来举行判断
feof
feof函数我们在上面已经做了根本介绍,它的作用就是,在文件读取竣事后,判断文件读取竣事的缘故原由是不是遇到了文件尾,我们来看看它的原型:
int feof ( FILE * stream );
函数的参数是要操纵的流,当文件是正常读取竣事,也就是文件是因为读到末尾了而竣事,就返回一个非0值,非正常读取竣事就返回0
ferror
ferror函数就是在文件读取竣事后,用来判断文件是否是错误读取竣事,和feof有点相似,只是判断的内容不同,我们来看看它的原型:
int ferror ( FILE * stream );
它的参数也是要操纵的流,假如文件是错误读取竣事,那么就返回非0值,假如没有错误读取竣事,也就是正常读取竣事了,就返回0
https://i-blog.csdnimg.cn/direct/9ff8da250d164d54ba380e1c2e04e660.png
判断文件读取竣事缘故原由示例
我们刚刚学习了feof和ferror函数,现在我们就来利用它们来判断文件竣事的缘故原由,要注意一个前提:当前目录下有一个文件test.txt,内里的内容是hello world!,接下来我们来看看怎么把这两个函数运用在实战上:
#include <stdio.h>
int main()
{
char arr;
FILE* pf = fopen("test.txt", "r");
if (pf == NULL)
{
perror("fopen");
return 1;
}
fgets(arr, 20, pf);
printf("%s\n", arr);
if (feof(pf))
{
printf("文件正常读取结束\n");
}
if (ferror(pf))
{
printf("文件错误读取结束\n");
perror("读取失败原因");
}
fclose(pf);
pf = NULL;
return 0;
}
我们将读取到的字符串放在了arr中,然后我们来判断文件是否正常读取竣事,假如正常读取竣事就打印一下这句话,假如错误读取竣事,那么就利用perror来打印一下读取失败的缘故原由,最后我们来看看代码运行结果:
三、文件缓冲区
当我们对文件写入数据后,假如步伐还在举行,而且没有关闭文件,那么我们会发现,我们写入的内容居然没有立刻就出现在文件中,而一旦关闭文件后写入的内容才出现在文件中,这是为什么呢?
这时我们就要引入文件缓冲区的概念了,ANSIC 尺度采⽤“缓冲⽂件系统” 处理的数据⽂件的,所谓缓冲⽂件系统是指系统⾃动地在内存中为步伐中每⼀个正在使⽤的⽂件开辟⼀块“⽂件缓冲区”
从内存向磁盘输出数据会先送到内存中的缓冲区,装满缓冲区后才⼀起送到磁盘上。假如从磁盘向计算机读⼊数据,则从磁盘⽂件中读取数据输⼊到内存缓冲区,布满缓冲区后再从缓冲区逐个地将数据送到步伐数据区(步伐变量等)
在文件中,有多种情况可以革新缓冲区,将缓冲区的数据写入文件,我们这里就讲一下常用的三种情况
[*]当缓冲区被装满后自动革新缓冲区,将数据写入文件
[*]当文件被关闭时,也会革新缓冲区,将数据写入文件
[*]利用fflush函数革新缓冲区,它可以几乎不受限定的随时革新缓冲区,使得缓冲区中的数据写入文件
那么缓冲区具体有多大呢?这个是不确定的,要看编译器的具体实现
我们今天就把文件操纵的大部分知识讲完了,有问题欢迎各人私信,bye~~
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页:
[1]