接上文,前两篇博客已经介绍了文件相关知识,上篇讲到了文件操作的顺序读写,接下来了解文件的随机读写操作和其他知识。 本文所涉及函数都是根据官网https://cplusplus.com/所得。
目录
文件读写操作,分为顺序读写和随机读写。
记得进行文件读写操作时,要先用fopen函数打开文件,之后要用fclose函数关闭文件。
我们现在来学习文件的随机读写。
5. 文件随机读写操作
文件的随机读写操作是什么呢?它不用按照从头到尾的顺序,程序员想从文件的哪个位置开始读或写都可以。
我们进行文件的随机读写操作,一般使用fseek、ftell、rewind这三个函数。使用这三个函数,只是改变文件指针的位置或偏移量,并不能直接对文件进行读写操作,之后还要配合文件顺序读写所涉及到的函数,大家可以到我的上一篇博客文件操作全解(中)了解~
5.1 fseek函数
fseek函数是根据文件指针的位置和偏移量来定位文件指针。
文件指针就是文件内容的光标,偏移量是指程序员想要开始进行读写操作的位置离文件指针现在所在位置相差的距离。
fseek函数的作用就是移动文件指针来达到想要的位置。
第一个参数是文件指针变量。
第二个参数是偏移量。
第三个参数代表着起始位置,可以填SEEK_SET(文件开头位置)、SEEK_CUR(文件指针当前位置)、SEEK_END(文件末尾)这三个值。
文件返回类型是int,若运行成功,返回零;若失败,回非零值。
操作一下:
我们现在先在文件里放入abcdefgh。很显然文件指针现在在文件开头位置。而字母d距离文件指针现在所在位置的偏移量是3。
如果我们想要读出字母‘d’,我们可以这样:
int main()
{ //文件打开
FILE* pf = fopen("text.txt", "r");
assert(pf);
//文件读操作
fseek(pf, 3, SEEK_SET);//使文件指针到字母d的前面位置
int i = fgetc(pf);
printf("%c\n", i);
//文件关闭
fclose(pf);
pf = NULL;
return 0;
}
结果:
我们也可以试试在第三个参数使用SEEK_CUR、SEEK_END。
我们先用fseek函数使文件指针随便到一个位置,比如字母f的前面。
然后试试在第三个参数使用SEEK_CUR,此时偏移量是-2.
试试fseek函数第三个参数使用SEEK_END。偏移量此时是-5.
5.2 ftell函数
ftell函数可以返回文件指针相对于起始位置的偏移量。(通俗说,ftell函数可以拿来计算当前文件指针距离文件开头位置的偏移量。)
ftell函数只有一个参数,是文件指针变量。
返回值就是所求偏移量。若运行成功,会返回文件指针当前位置的偏移量。若失败,返回 -1L,并将 errno 设置为系统特定的正值。
5.3 rewind函数
rewind函数可以让文件指针的位置回到文件的起始位置。
函数参数是文件指针变量,无返回类型。
操作一下:
我们本来让fseek函数移动了文件指针位置,使用了rewind后,通过fgetc函数读出的字母a,很明显看出文件指针刚才已经回到了起始位置。
6. 文件读取结束的判定
文件会读取结束,是什么原因呢?
要么是遇到了文件末尾,
要么是读取时发生了错误。
6.1 文本文件
那程序员一般可以怎样判断文件是否读取结束呢?
(此时的问题只是问怎样判断文件读取结束,并不是判断哪种原因导致文件读取结束~)
文本文件读取是否结束,可判断返回值是否为EOF,或者NULL。我们可以用fgetc函数(EOF)和fgets函数(NULL)来判断。
简单回忆一下这两个函数的返回值:
fgetc函数:
如果读取正常,返回的是读取到字符的ASCII码值;
如果读取的过程中遇到文件末尾,或者发生错误,就返回EOF。
fgets函数:
如果读取正常,返回的是存储读取到的字符串的字符数组的地址
如果读取的过程中遇到文件末尾,或者发生错误,就返回NULL。
fgetc函数 | 判断是否是EOF |
fgets函数 | 判断返回值是否为NULL |
我们若想判断是什么原因导致文件读取结束了?
(文本文件和二进制文件都适用)
我们可以通过下列这两个函数来判断:
feof函数 | 是否遇到文件末尾 |
ferror函数 | 是否发生错误 |
简单学习一下这两个函数:
feof函数
我们主要关心它的返回类型。
若文件遇到文件末尾,feof函数会返回非零值。若没有遇到文件末尾,它会返回0.
ferror函数
我们也是看它的返回类型。
若是遇到文件读取错误,ferror函数会返回非零值;若没有遇到错误,它会返回0.
简单操作一下:
运行代码:
int main()
{
//文件内容是abcdefgh
int c;
//文件打开
FILE* pf = fopen("text.txt", "r");
assert(pf);
//使用fgetc函数,当文件读取结束时会返回EOF.
while ((c = fgetc(pf))!=EOF)
{
putchar(c);
}
printf("\n");
//判断是什么原因导致文件读取结束的
if (ferror(pf))
printf("遇到文件读取错误了!\n");
else if (feof(pf))
printf("遇到文件末尾了!\n");
else
printf("什么都没有遇到。\n");
//文件关闭
fclose(pf);
pf = NULL;
return 0;
}
结果:
6.2 二进制文件
二进制文件是否读取结束,可以判断返回值是否小于实际要读的个数。
可以使用fread函数来判断返回值是否小于实际要读的个数。
简单回忆一下fread函数的返回值:
fread函数会返回成功读取到的数据个数。
若读取正常,该返回值等于实际要读的个数。
若发生读取错误或达到文件末尾,该返回值会小于实际要读的个数。
7. 文件缓冲区
ANSIC标准采用“缓冲文件系统”处理的数据文件的。
所谓缓冲文件系统是指系统自动地在内存中为程序中每一个正在使用的文件开辟一块“文件缓冲区”。
(大家根据下图和文字一起理解一下)
从内存向磁盘输出数据会先送到内存中的缓冲区,装满缓冲区后才一起送到磁盘上。
如果从磁盘向计算机读入数据,则从磁盘文件中读取数据输入到内存缓冲区(充满缓冲区),然后再从缓冲区逐个地将数据送到程序数据区(程序变量等)。缓冲区的大小根据C编译系统决定的。
就是因为有文件缓冲区的存在,使用c语言进行文件操作时,需要刷新文件缓冲区或者在文件操作结束时关闭文件(这样也会刷新文件缓冲区)。
如果不做,很可能会导致读写文件的问题。
这也是我们为什么进行文件操作时,要遵守三步骤了:打开文件---文件读写操作---关闭文件。
到这为止,已经全部介绍完文件操作的知识了,我们下一篇再见~