前言
在文件操作函数(二)中,我们介绍了文件的顺序读写函数,即挨着顺序对文件中的数据进行输入或输出操作的函数。但是若只能规规矩矩地,从前到尾对文件进行输入输出操作,那么就比较笨拙,为了能更加灵活地对文件进行输入输出操作,出现了另一类文件操作函数,使得我们可以对文件进行随机读写。
需要注意的是,随机读写并非胡乱读写文件的某一位置,而是按照操作者的意愿,随机读写文件的某一位置。
例如,data.txt文件中的内容是"abcdef",执行完以下代码后,我们如何再次读取文件开头的数据(字符’a’)。
#include <stdio.h>
#include <string.h>
#include <errno.h>
int main()
{
//打开文件
FILE* pf = fopen("data.txt", "r");
if (pf == NULL)
{
printf("%s\n", strerror(errno));
return 1;//文件打开失败,失败返回
}
//用字符输入函数读取文件信息
int ch = fgetc(pf);
printf("%c\n", ch);//观察第一次读取到的字符
ch = fgetc(pf);
printf("%c\n", ch);//观察第二次读取到的字符
//关闭文件
fclose(pf);
pf = NULL;
return 0;
}
第一次读取字符时,指针位于文件开头,读取到了第一个字符以后,指针就会自动向后移动,指向后面的内容:
还未读取时,文件指针指向文件信息区的起始位置:
读取’a’字符以后,文件指针自动跳过字符’a’,指向下一个字符:
再次读取,就读取到的是字符’b’了,文件指针再次后移:
所以,如果我们继续用fgetc函数向后读取文件内容,那么读取到的就是字符’c’了。
那么,在读取了字符’a’和字符’b’后,我们如何再次读取到字符’a’,或是不读取下一个字符’c’,而读取其后的某一指定位置的数据呢?
这就是所谓的文件的随机读写了。
fseek函数
int fseek( FILE *stream, long offset, int origin );
fseek函数的第一个参数既是要移动位置的文件指针,第三个参数是“初始位置”(并非文件信息区的起始位置),第二个参数是文件指针经操作后相对于这个“起始位置”的偏移量,单位为字节。fseek函数如果调用成功,则返回0;若调用失败,则返回一个非0的值。
关于fseek函数的第三个参数,可以有以下三种形式:
参数形式 | 代表意义 |
---|---|
SEEK_CUR | 文件指针的当前位置 |
SEEK_SET | 文件开头 |
SEEK_END | 文件末尾 |
所以,如果我们用fseek函数,对上述例题中pf指针进行操作,使其下一次读取字符时能读取到字符’a’,则有以下三种写法:
1.让文件指针相对于其当前位置向前偏移2个字节。
fseek(pf, -2, SEEK_CUR);//调整文件指针位置
ch = fgetc(pf);//读取到字符'a'
printf("%c\n", ch);
2.让文件指针相对于文件开头偏移0个字节(即指向文件开头)。
fseek(pf, 0, SEEK_SET);//调整文件指针位置
ch = fgetc(pf);//读取到字符'a'
printf("%c\n", ch);
3.让文件指针相对于文件末尾向前偏移6个字节。
fseek(pf, -6, SEEK_END);//调整文件指针位置
ch = fgetc(pf);//读取到字符'a'
printf("%c\n", ch);
ftell函数
为了更好地明确文件指针位于什么位置,于是出现了ftell函数,它用于计算当前文件指针相对于起始位置的偏移量。
long ftell( FILE *stream );
ftell函数的参数是一个文件指针。ftell函数调用成功,则返回文件指针相对于起始位置的偏移量;若调用失败,则返回 - 1。
例如,我们要计算上述例题中,读取了两个字符后,pf相对于起始位置的偏移量,我们可以这样计算:
long Offset = ftell(pf);
此时,变量Offset中存放的就是pf指针相对于起始位置的偏移量。
rewind函数
void rewind( FILE *stream );
rewind函数的作用是让传入的文件指针返回文件的起始位置。例如,在上述例题中,我们可以直接让文件指针返回文件的起始位置,这样就能读取到字符’a’:
rewind(pf);//调整文件指针位置
ch = fgetc(pf);//读取到字符'a'
printf("%c\n", ch);
拓:用fseek函数与ftell函数求文件大小
求一个文件的大小其实很简单,你只需要将文件指针移到该文件末尾,然后求文件指针相对于起始位置的偏移量即可。
fseek(pf, 0, SEEK_END);//将文件指针置于文件末尾
int FileLen = ftell(pf);//求文件指针相对于文件起始位置的偏移量
fseek(pf, 0, SEEK_SET);//将文件指针放回文件开头