
导读
大家好,很高兴又和大家见面啦!!!
在上一篇内容中,我们系统学习了C语言文件操作中的顺序读写函数,掌握了如何按部就班地对文件内容进行处理。
无论是字符级的 fgetc/fputc,字符串操作的 fgets/fputs,还是格式化的 fscanf/fprintf,以及二进制的 fread/fwrite,这些函数都遵循着"从头到尾、依次处理"的顺序读写模式。
然而,在实际编程中,我们常常需要更灵活的文件操作方式。今天,我们将进入文件操作的另一个重要领域——随机读写,学习如何精准控制文件中的读写位置。让我们开始探索以下五个核心函数:
fseek —— 设置文件中的位置指示器位置ftell —— 获取文件中的位置指示器位置rewind —— 重置文件中的位置指示器位置fgetpos —— 获取文件中的位置指示器位置fsetpos —— 设置文件中的位置指示器位置fseek
上图给出了函数用法的介绍,我们可以看到该函数不仅能够对文本文件使用,还可以对二进制文件使用;

上图给我们介绍了函数的三个参数与返回值,从这两张图片介绍中,我们可以了解该函数的使用方法:
stream :指向识别流的 FILE 对象指针offset :文件中光标的位置 origin 的参考值中偏移的字节数ftell 函数获取的返回值origin :为 offset 参考的位置 SEEK_SET : 文件开头SEEK_CUR :文件指针的当前位置SEEK_END :文件末尾origin 的参考位置的偏移量 offset 定义0 或者由先前调用 ftell 函数时的返回值,并且 origin 的参考值必须为 SEEK_SET ,即文件开头;0ferror)从用法中我们可以看到,该函数的使用与 ftell 函数是分不开的,因此我们下面直接来看一下 ftell 函数应该如何使用;
ftell
该函数的使用方法为:
stream :指向识别流的 FILE 对象指针-1L ,并将 errno 设置为系统的特定正值该函数的使用我们可以简单的理解为,函数会获取文件中的光标位置:
fseek 时作为函数参数,让 fseek 将光标的位置恢复到当前位置现在对于 fseek 和 ftell 这两个函数我们就能够理解为:
ftell 用于获取文件中的光标位置fseek 用于设置文件中的光标位置接下来我们就可以尝试着使用这两个函数了:
void test1() {
FILE* pf = fopen("C:\\Users\\LIQIAN\\Desktop\\data.txt", "r+");
if (pf == NULL) {
perror("fopen");
return;
}
// 通过 ftell 获取文件中的光标当前位置
long int index = ftell(pf);
// 检查返回值
if (index == -1L) {
perror("ftell");
fclose(pf);
pf = NULL;
return;
}
// 通过 fgetc 读取当前位置的文本信息
int ch = fgetc(pf);
while (ch != EOF) {
printf("ch = %c\n", ch);
ch = fgetc(pf);
}
// 通过 fseek 设置文件中的光标位置
int set = fseek(pf, index, SEEK_SET);
// 由于我们打开的为文本文件,因此 origin 的值必须为文件开头(SEEK_SET)
if (set != 0) {
perror("fseek");
fclose(pf);
pf = NULL;
return;
}
// 再一次读取当前位置的元素
ch = fgetc(pf);
printf("ch = %c\n", ch);
fclose(pf);
pf = NULL;
}这里的测试代码逻辑比较简单:
ftell 记录文件当前的光标起始位置fgetc 进行内容读取,直到光标移动到文件末尾fseek 重新设置光标的位置fgetc 来读取当前位置的内容下面我们就来运行以下该测试代码:

从测试结果中可以看到,文件刚打开时,光标的位置为文件开头,当我们通过 ftell 记录了此时的位置后,我们通过 fgetc 移动了光标,不管光标最后在哪里,我们都可以通过 fseek 函数将光标设置到最初我们记录的位置;
那可能有朋友会问,如果我们在记录光标的起始位置时,光标并不在文件开头,这时我们需要将光标重置到文件开头,应该怎么办呢?
此时有两种办法:
offset 参数值置为 0 ,即 int set = fseek(pf, 0, SEEK_SET);rewind 函数重置光标位置接下来,我们就来看看 rwind 函数的具体用法;
rewind
该函数的用法如下:
stream :指向标识流的 FILE 对象指针该函数简单的理解就是用于重置文件内部的光标位置。接下来我们就来对其进行测试:
void test2() {
FILE* pf = fopen("C:\\Users\\LIQIAN\\Desktop\\data.txt", "r+");
if (pf == NULL) {
perror("fopen");
return;
}
// 通过 fgetc 先读取一定的文本信息
for (int i = 0; i < 3; i++) {
int ch = fgetc(pf);
printf("ch = %c ", ch);
}
printf("\n");
// 通过 ftell 获取文件中的光标当前位置
long int index = ftell(pf);
// 检查返回值
if (index == -1L) {
perror("ftell");
fclose(pf);
pf = NULL;
return;
}
// 通过 fgetc 读取当前位置的文本信息
int ch = fgetc(pf);
while (ch != EOF) {
printf("ch = %c ", ch);
ch = fgetc(pf);
}
printf("\n");
// 通过 fseek 设置文件中的光标位置
int set = fseek(pf, index, SEEK_SET);
// 由于我们打开的为文本文件,因此 origin 的值必须为文件开头(SEEK_SET)
if (set != 0) {
perror("fseek");
fclose(pf);
pf = NULL;
return;
}
// 再一次读取当前位置的元素
ch = fgetc(pf);
printf("ch = %c\n", ch);
// 通过 rewind 重置光标位置
rewind(pf);
// 再一次读取当前位置的元素
ch = fgetc(pf);
printf("ch = %c\n", ch);
fclose(pf);
pf = NULL;
}我们此时的测试逻辑很简单:
fgetc 读取数据来移动光标ftell 来记录光标此时的位置fgetc 读取数据,进一步移动光标fseek 来恢复光标的位置rewind 来重置光标的位置下面我们就来对其测试一下:

可以看到,当我们使用 rewind 后,光标的位置就从我们最开始记录的 l 处重置为了文件开头 H 处。
因此当我们在对文件进行操作时,如果我们需要重置光标的位置,我们就可以通过 rewind 实现。
fgetpos
该函数的用法如下所示:
stream :指向标识流的 FILE 对象指针pos :指向 fpos_t 对象指针stream 中获取到的当前位置信息填入到 pos 中 0errno 会被设置为平台特定的正值,并且函数返回一个非零值fpos_t在函数的用法介绍中,我们看到了一个新的类型:fpos_t 。那么在使用该函数前,我们先来认识一下这个新的类型:

该类型就是专门用于记录文件中的光标位置的类型,该类型的变量中存储的信息,通常是通过 fgetpos 函数进行填充,并且其变量中的信息不能直接读取,只能够在调用 fsetpos 时,作为参数使用。
那也就是说,fgetpos 与 fsetpos 这两个函数应该搭配起来使用,那么接下来我们就一起来看看如何 fsetpos 的具体用法;
fsetpos
该函数的用法如下所示:
stream :指向标识流的 FILE 对象指针pos :指向 fpos_t 对象指针stream 的当前位置恢复到 pos 中 0errno 会被设置为平台特定的正值,并且函数返回一个非零值该函数的用法我们可以简单的理解为,将文件中的光标位置恢复到 pos 中存储的位置。
这里需要注意的是,
pos_t的对象中存储的信息只能通过fgetpos获取,我们无法直接对其进行赋值操作!!!
接下来我们就来尝试着使用一下这两个函数:
void test3() {
FILE* pf = fopen("C:\\Users\\LIQIAN\\Desktop\\data.txt", "r");
if (pf == NULL) {
perror("fopen");
return;
}
// 通过 fgetc 读取数据来移动光标
for (int i = 0; i < 3; i++) {
int ch = fgetc(pf);
printf("ch = %c\n", ch);
}
printf("\n");
// 记录光标位置变量
fpos_t pos;
// 通过 fgetpos 获取当前光标位置
int get = fgetpos(pf, &pos);
// 通过 fgetc 移动光标
int ch = fgetc(pf);
while (ch != '!') {
printf("ch = %c\n", ch);
ch = fgetc(pf);
}
printf("\nch = %c\n", ch);
// 通过 fsetpos 来恢复光标位置
int set = fsetpos(pf, &pos);
ch = fgetc(pf);
printf("\nch = %c\n", ch);
fclose(pf);
pf = NULL;
}这一次我们测试的逻辑与前面的逻辑一致:
fgetc 来移动光标fgetpos 来获取光标位置信息fgetc 来移动光标fsetpos 来设置光标位置下面我们就来测试一下:

可以看到,函数 fgetpos 与 fsetpos 二者配合起来使用,同样能够达到光标定位与设置的效果。
现在问题来了,这两个函数与前面我们介绍的 ftell 和 fseek 之间有什么不同呢?
不管是 ftell 与 fseek 的搭配使用,还是 fgetpos 与 fsetpos 的搭配使用,他们都是用来完成两件事:
这二者之间不同的地方在于—— 记录光标位置的方式不同:
ftell 是通过 long int 类型的变量来记录光标的位置fgetpos 则是通过 fpos_t 类型的变量来记录光标位置因此,这就导致了二者能够处理的文件大小有所区别:
long int 时,我们再通过 ftell 来记录光标的位置就会出现问题fgetpos 是通过 fpos_t 来记录,因此,我们不需要考虑光标的位置是否会存在溢出的情况也就是说,当我们处理大文件时,我们选择使用 fgetpos 和 fsetpos 会更加保险一点。
通过今天的学习,我们深入掌握了C语言中实现文件随机读写的五个核心函数。让我们简单回顾一下本篇的重要内容:
函数功能总结:
fseek:精确定位文件光标,支持三种参考位置(文件头、当前位置、文件尾)
ftell:获取当前光标位置,为 fseek 提供定位依据
rewind:快速重置光标到文件开头,并清除错误指示器
fgetpos:使用fpos_t类型安全记录光标位置
fsetpos:与 fgetpos 配合,精准恢复光标位置
关键区别:
ftell/fseek 使用 long 类型,适合一般文件操作
fgetpos/fsetpos 使用 fpos_t 类型,更适合大文件处理
实践价值:
今天的内容到这里就全部结束了,在下一篇内容中我们将介绍文件操作的错误处理机制,大家记得关注哦!
如果大家觉得这篇博客有帮助,请: 👍 点赞支持 - 您的认可让我更有动力创作 ⭐ 关注博主 - 获取更多C语言技术干货 💾 收藏文章 - 方便随时回顾复习 💬 评论留言 - 有任何问题欢迎交流讨论 🔄 转发分享 - 帮助更多需要的朋友
最后感谢各位朋友的支持,咱们下一篇再见!!!