C语言文件随机读写的完全指南
目录
- 导读
- 一、fseek
- 二、ftell
- 2.1 函数介绍
- 2.2 函数使用
- 三、rewind
- 3.1 函数介绍
- 3.2 函数使用
- 四、fgetpos
- 4.1 函数介绍
- 4.2 fpos_t
- 五、fsetpos
- 5.1 函数介绍
- 5.2 函数使用
- 5.3 函数比较
- 5.3.1 相同点
- 5.3.2 不同点
- 结语
导读
无论是字符级的 fgetc/fputc
,字符串操作的 fgets/fputs
,还是格式化的 fscanf/fprintf
,以及二进制的 fread/fwrite
,这些函数都遵循着"从头到尾、依次处理"的顺序读写模式。
然而,在实际编程中,我们常常需要更灵活的文件操作方式。今天,我们将进入文件操作的另一个重要领域——随机读写,学习如何精准控制文件中的读写位置。让我们开始探索以下五个核心函数:
fseek
—— 设置文件中的位置指示器位置ftell
—&mdaphpsh; 获取文件中的位置指示器位置rewind
—— 重置文件中的位置指示器位置fgetpos
—— 获取文件中的位置指示器位置fsetpos
—— 设置文件中的位置指示器位置
一、fseek
上图给出了函数用法的介绍,我们可以看到该函数不仅能够对文本文件使用,还可以对二进制文件使用;
上图给我们介绍了函数的三个参数与返回值,从这两张图片介绍中,我们可以了解该函数的使用方法:
- 向函数中传入3个参数
stream
:指向识别流的FILE
对象指针offset
:文件中光标的位置- 二进制文件中:从
origin
&nbsandroidp;的参考值中偏移的字节数 - 文本文件中:0 或者由
ftell
函数获取的返回值
- 二进制文件中:从
origin
:为offset
参考的位置SEEK_SET
: 文件开头SEEK_CUR
:文件指针的当前位置SEEK_END
:文件末尾
- 函数会将与流关联的文件内部的光标设置为一个新位置:
- 二进制文件:新位置由
origin
的参考位置的偏移量offset
定义 - 文本文件:新位置为
0
或者由先前调用ftell
函数时的返回值,并且origin
的参考值必须为SEEK_SET
,即文件开头; - 当函数在这些参考值之外调用其他值,是否支持还取决于特定的系统和库的实现。即若当前系统支持,那此时的使用方法无法移植。
- 二进制文件:新位置由
- 函数在完成设置后,会给出相应的返回值:
- 设置成功,则函数返回
0
- 设置失败,则函数返回非零值
- 如果发生读取或写入错误,则函数会设置错误指示器(
ferror
)
- 设置成功,则函数返回
从用法中我们可以看到,该函数的使用与 ftell
函数是分不开的,因此我们下面直接来看一下 ftell
函数应该如何使用;
二、ftell
2.1 函数介绍
该函数的使用方法为:
- 向函数中传入一个参数:
stream
:指向识别流的FILE
对象指针
- 函数会从流中获取当前位置指示器的值
- 成功时,则将当前值返回
- 失败时,则返回
-1L
,并将errno
设置为系统的特定正值
2.2 函数使用
该函数的使用我们可以简单的理解为,函数会获取文件中的光标位置:
- 当文件为二进制文件时,函数的返回值为文件光标从文件开头开始的偏移量
- 当文件为文本文件时,函数的返回值可能没有实际意义,但是仍可在调用
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
3.1 函数介绍
该函数的用法如下:
- 向函数中传入一个参数:
stream
:指向标识流的FILE
对象指针
- 函数会清除流中的文件末尾内部指示器和错误内部指示器,并将文件内部的位置指示器设置为文件开头
3.2 函数使用
该函数简单的理解就是用于重置文件内部的光标位置。接下来我们就来对其进行测试:
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
读取数据来移动光标 - 完成写入后,通过&nbsCAlTxoyUlFp;
ftell
来记录光标此时的位置 - 接下来,我们继续通过
fgetc
读取数据,进一步移动光标 - 之后,我们再通过
fseek
来恢复光标的位置 - 最后,我们再通过
rewind
来重置光标的位置
下面我们就来对其测试一下:
可以看到,当我们使用 rewind
后,光标的位置就从我们最开始记录的 l
处重置为了文件开头 H
处。
因此当我们在对文件进行操作时,如果我们需要重置光标的位置,我们就可以通过 rewind
实现。
四、fgetpos
4.1 函数介绍
该函数的用法如下所示:
- 向函数中传入两个参数:
stream
:指向标识流的FILE
对象指针pos
:指向fpos_t
对象指针
- 函数会将从
stream
中获取到的当前位置信息填入到pos
中- 成功时,函数返回
0
- 发生错误时,
errno
会被设置为平台特定的正值,并且函数返回一个非零值
- 成功时,函数返回
4.2 fpos_t
在函数的用法介绍中,我们看到了一个新的类型:fpos_t
。那么在使用该函数前,我们先来认识一下这个新的类型:
该类型就是专门用于记录文件中的光标位置的类型,该类型的变量中存储的信android息,通常是通过 fgetpos
函数进行填充,并且其变量中的信息不能直接读取,只能够在调用 fsetpos
时,作为参数使用。
那也就是说,fgetpos
与 fsetpos
这两个函数应该搭配起来使用,那么接下来我们就一起来看看如何 fsetpos
的具体用法;
五、fsetpos
5.1 函数介绍
该函数的用法如下所示:
- 向函数中传入两个参数:
stream
:指向标识流的FILE
对象指针pos
:指向fpos_t
对象指针
- 函数会将
stream
的当前位置恢复到pos
中- 成功时,函数返回
0
- 发生错误时,
errno
会被设置为平台特定的正值,并且函数返回一个非零值
- 成功时,函数返回
5.2 函数使用
该函数的用法我们可以简单的理解为,将文件中的光标位置恢复到 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
之间有什么不同呢?
5.3 函数比较
5.3.1 相同点
不管是 ftell
与 fseek
的搭配使用,还是 fgetpos
与 fsetpos
的搭配使用,他们都是用来完成两件事:
- 记录光标位置
- 设置光标位置
5.3.2 不同点
这二者之间不同的地方在于—— 记录光标位置的方式不同:
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语言文件随机读写的完全指南的详细内容,更多关于C语言文件随机读写的资料请关注编程客栈(www.devze.com)其它相关文章!
精彩评论