C语言fseek与ftell函数详解:随机访问文件与大小获取实战
掌握 C 语言中的 fseek 和 ftell 函数是实现高效文件随机访问的关键。fseek 允许开发者根据指定起点(文件头、当前位置或文件尾)调整文件指针位置,支持负数或正数偏移;ftell 则用于返回当前指针相对于文件首的字节偏移量,常用来获取文件总长度。结合使用这两个函数,可以灵活处理二进制数据修改、大文件动态内存读取等场景。
结果或目标
在实际开发中,顺序读写往往无法满足需求。例如需要更新记录文件的最后一条数据,或者在不加载整个文件的情况下一次性读取其内容。本指南将展示如何利用 fseek 精准定位以及如何利用 ftell 获取文件大小,从而完成这些任务。
准备条件
- C 语言标准库:
<stdio.h>提供文件操作接口,<stdlib.h>提供内存分配接口。 - 文件模式:确保以二进制模式(如 "rb+", "wb")打开文件,特别是在处理结构体或精确字节偏移时,文本模式下的换行符转换可能导致偏移计算错误。
- 数据类型:理解
long类型用于表示偏移量和文件位置指示器返回值。
真实操作顺序
第1步:使用 fseek 修改文件指针位置
目的: 将文件指针移动到指定位置,以便进行非顺序读写(如覆盖特定位置的数据)。
入口: int fseek(FILE *stream, long offset, int whence);
动作说明:
stream:已打开的文件指针。offset:偏移量。正数表示向文件末尾方向移动,负数表示向文件开头方向移动。whence:起始基准点,常用常量包括:SEEK_SET:文件开头。SEEK_CUR:文件指针当前所在位置。SEEK_END:文件末尾。
注意事项: 若执行成功返回 0;失败返回非 0 值。需要注意的是,即使偏移量超出文件物理边界(如末尾之后或开头之前),某些实现也可能返回 0 但不改变文件状态或产生未定义行为,因此需谨慎使用。
第2步:在结构体文件中覆盖最后一条记录
场景: 假设有一个存储学生信息的二进制文件,需要修改最后一条学生的成绩而不影响其他数据。
操作步骤:
- 打开文件为读写模式:
fopen("student.dat", "rb+")。 - 使用
fseek定位到倒数一个结构体的位置:fseek(fp, -1L * sizeof(STU), SEEK_END)。这里从文件末尾往前偏移一个结构体的大小。 - 使用
fwrite写入新数据覆盖旧数据。 - 关闭文件。
#include <stdio.h>
#define N 5
typedef struct student {
long sno;
char name[10];
float score[3];
} STU;
void updateLastRecord(char* filename, STU n) {
FILE* fp;
// 以二进制读写模式打开
fp = fopen(filename, "rb+");
if (fp == NULL) return;
// 关键步骤:定位到最后一个记录
fseek(fp, -1L * sizeof(STU), SEEK_END);
// 覆盖写入
fwrite(&n, sizeof(STU), 1, fp);
fclose(fp);
}
int main() {
STU students[N] = {
{10001, "MaChao", {91, 92, 77}},
{10002, "CaoKai", {75, 60, 88}},
{10003, "LiSi", {85, 70, 78}},
{10004, "FangFang", {90, 82, 87}},
{10005, "ZhangSan", {95, 80, 88}}
};
STU newStudent = {10006, "ZhaoSi", {55, 70, 68}};
// 1. 创建测试文件
FILE* fp = fopen("student.dat", "wb");
fwrite(students, sizeof(STU), N, fp);
fclose(fp);
// 2. 执行覆盖操作
updateLastRecord("student.dat", newStudent);
// 3. 验证结果:重新读取并打印
printf("Data after modification:\n");
fp = fopen("student.dat", "rb");
STU buffer[N];
fread(buffer, sizeof(STU), N, fp);
fclose(fp);
for (int i = 0; i < N; i++) {
printf("No: %ld, Name: %-8s, Scores: %.2f, %.2f, %.2f\n",
buffer[i].sno, buffer[i].name, buffer[i].score[0],
buffer[i].score[1], buffer[i].score[2]);
}
return 0;
}
第3步:使用 ftell 获取当前文件指针位置
目的: 确定文件指针当前距离文件开头的字节数,常用于获取文件大小或调试定位。
入口: long ftell(FILE *stream);
动作说明: 该函数返回当前文件位置指示器的值。对于二进制文件,这通常等于文件的绝对偏移量(字节数)。
第4步:结合 fseek 和 ftell 读取整个文本文件
场景: 动态分配内存以一次性读取整个文本文件内容,避免多次 realloc。
操作步骤:
- 以只读方式打开文件:
fopen("1.txt", "r")。 - 将指针移动到文件末尾:
fseek(fp, 0L, SEEK_END)。 - 使用
ftell获取文件大小:flen = ftell(fp)。 - 分配内存:
p = malloc(flen + 1)(预留 \0 结束符空间)。 - 将指针重置到文件开头:
fseek(fp, 0L, SEEK_SET)。 - 一次性读取全部内容:
fread(p, flen, 1, fp)。 - 添加字符串结束符
p[flen] = '\0'。
#include <stdio.h>
#include <stdlib.h>
int readFileIntoBuffer(const char* filename) {
FILE* fp;
long flen;
char* p;
if ((fp = fopen(filename, "r")) == NULL) {
printf("File open error\n");
return -1;
}
// 1. 定位到末尾获取大小
fseek(fp, 0L, SEEK_END);
flen = ftell(fp);
// 异常检查:如果文件无法获取位置或为空处理
if (flen <= 0) {
fclose(fp);
return -1;
}
// 2. 分配内存
p = (char*)malloc(flen + 1);
if (p == NULL) {
fclose(fp);
return -1;
}
// 3. 回到开头读取
fseek(fp, 0L, SEEK_SET);
fread(p, flen, 1, fp);
p[flen] = '\0'; // 确保是合法C字符串
printf("%s\n", p);
// 4. 清理
free(p);
fclose(fp);
return 0;
}
简要总结
fseek 提供了对文件内部任意位置的精确控制权,配合 SEEK_END 可轻松实现基于文件长度的反向寻址;ftell 则是测量“路径”长度的工具。两者结合,不仅能让二进制数据修改更高效,也能简化大文本文件的内存读取逻辑。在实际编程中,务必注意文件模式(二进制 vs 文本)对字节计数的影响,并在操作前做好资源释放检查。
以上就是C语言中fseek函数和ftell函数的详细内容,更多关于C语言文件操作的资料请关注本站其它相关文章!
免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。









