4. 文件的随机读写
文件的随机读写是指能够在文件的任意位置直接读取或写入数据,而无需按顺序从头到尾遍历内容。
文件的随机读写常用于二进制方式读写文件的过程中。对于文本方式读写文件时,由于每一行字符串的长度难于确定。因此很少使用文件的随机读写。
随机读写通过移动文件的读写位置来快速定位到指定位置,实现高效的数据操作。在软件使用的过程中,在听 MP3 音乐时,我们向后拖动滚动条来跳过前面内容进行播放,实际就可能用到文件的随机读操作。
应用场景
- 需改部分内容。
- 高效查询。
- 二进制文件处理。
- 日志追加。
文件的随机读写相关的函数
函数
说明
long ftell(FILE *stream);返回当前文件流
stream 的读写位置。int fseek(FILE *stream, long offset, int whence);设置当前文件流的读写位置,成功返回0,失败返回 -1。
void rewind(FILE *stream);将文件的读写位置设置为 0。
说明:
- stream 参数的实际要操作的文件流对象。
- offset 参数是相对位置的偏移量。
- 大于 0 的数代表向文件末尾方向移动。
- 小于 0 的数代表向文件头方向移动。
- 0 表示相对于某个位置不变。
- whence 参数是只相对于哪里进行移动。
- SEEK_SET(值为 0),代表从文件头开始偏移。
- SEEK_CUR(值为 1),代表从当前读写位置开始偏移。
- SEEK_END(值为 2),代表从文件尾开始偏移。
示例:
上节课我们已经生成了以个长度为 80 字节的文件 mydata.txt 用来保存了两个学生的信息。我们已经知道内部的存储格式,接下来我们使用文件的随机读写获取文件中的部分信息。
// filename: file_random_read.c
#include <stdio.h>
struct student {
char name[32];
int age;
int score;
};
int main(int argc, char * argv[]) {
FILE * pf = NULL; // 用于保存已经打开的文件
struct student astu; // 用于保存一个学生的信息
int age; // 用于保存一个学生的年龄。
// 以二进制 读 的方式打开文件
pf = fopen("mydata.txt", "rb");
if (NULL == pf) {
perror("打开文件 mydata.txt");
return -1;
}
// 获取初始时文件的读写位置。
printf("打开文件时,文件的读写位置是: %ld\n", ftell(pf));
// 将读写位置定位到文件末尾,然后 ftell 的返回值就是文件的长度。
fseek(pf, 0, SEEK_END);
// 获取当前文件的读写位置。
printf("文件的长度是: %ld\n", ftell(pf));
// 从当前位置向前移动 40 个字节。
fseek(pf, -40, SEEK_CUR);
// 打印文件的当前读写位置。
printf("第二个学生信息在文件的读写位置是: %ld\n", ftell(pf));
// 读取第二个学生的信息
if (fread(&astu, sizeof(astu), 1, pf) < 1) {
printf("读取第二个学生信息失败\n");
goto exit_main; // 关闭文件后退出
}
printf("姓名: %s, 年龄: %d, 成绩: %d\n", astu.name, astu.age, astu.score);
// 打印当前的读写位置信息
printf("读取第二个学生信息后的文件读写位置是 :%ld\n", ftell(pf));
// 重新定位文件头 第 32 个字节的位置,读取第一个学生的年龄信息
fseek(pf, 32, SEEK_SET);
if (fread(&age, sizeof(age), 1, pf) < 1) {
printf("读取第一个学生的年龄失败!\n");
goto exit_main;
}
printf("第一个学生的年龄是: %d\n", age);
exit_main:
// 关闭文件
fclose(pf);
return 0;
}
编译和运行结果如下:
weimingze@mzstudio:~$ ls
file_random_read.c mydata.txt
weimingze@mzstudio:~$ ls -l mydata.txt
-rw-r--r-- 1 weimingze weimingze 80 12月 6 10:16 mydata.txt
weimingze@mzstudio:~$ gcc -o file_random_read file_random_read.c
weimingze@mzstudio:~$ ./file_random_read
打开文件时,文件的读写位置是: 0
文件的长度是: 80
第二个学生信息在文件的读写位置是: 40
姓名: lisi, 年龄: 19, 成绩: 80
读取第二个学生信息后的文件读写位置是: 80
第一个学生的年龄是: 18
从上述运行结果可以看出,使用 fseek 可以任意定位一个文件的某个位置进行读写,只要这个文件的格式是已知的,这种定位读写的方法是可行的,并且效率高。
实验:
自己写程序,尝试使用 fseek 和 ftell 进行文件的随机定位的读写操作。