在c++的文件操作场景中,经常需要跳过文件头部内容、读取指定位置的数据或者向文件的特定位置写入内容,这时候就需要修改文件指针的位置。c++提供了两套文件操作体系,分别对应c风格的文件操作函数和c++标准库的文件流类,修改文件指针的核心函数分别是fseek和seekg,两者的偏移量计算逻辑有相似之处也有区别,下面通过实战案例详细说明。

一、c风格文件操作:fseek函数用法
fseek是c标准库提供的用于设置文件指针位置的函数,定义在cstdio头文件中,适用于FILE*类型的文件指针。它的函数原型为:
#include <cstdio> int fseek(FILE* stream, long offset, int origin);
参数含义如下:
- stream:已经打开的文件指针,必须是可读写或者可定位的文件流
- offset:偏移量,单位为字节,正数表示向文件末尾方向移动,负数表示向文件开头方向移动
- origin:偏移的起始位置,有三个可选值:SEEK_SET(文件开头)、SEEK_CUR(当前文件指针位置)、SEEK_END(文件末尾)
下面通过一个实战案例演示fseek的偏移量计算:假设我们有一个test.txt文件,内容为"abcdefghij",共10个字节(每个字符占1字节)。
#include <cstdio>
#include <cstring>
int main() {
FILE* fp = fopen("test.txt", "r+b"); // 以读写方式打开二进制文件,避免换行符转换影响偏移
if (fp == nullptr) {
return -1;
}
// 1. 从文件开头偏移3个字节,此时指针指向第4个字符'd'
fseek(fp, 3, SEEK_SET);
char c;
fread(&c, 1, 1, fp);
// 此时c的值为'd'
// 2. 从当前位置再偏移2个字节,指针指向第6个字符'f'
fseek(fp, 2, SEEK_CUR);
fread(&c, 1, 1, fp);
// 此时c的值为'f'
// 3. 从文件末尾向前偏移2个字节,指针指向第9个字符'i'
fseek(fp, -2, SEEK_END);
fread(&c, 1, 1, fp);
// 此时c的值为'i'
fclose(fp);
return 0;
}
二、c++文件流:seekg函数用法
seekg是c++标准库中istream类的方法,主要用于输入文件流ifstream,用于设置读指针的位置,对应的写指针设置函数是seekp。如果是fstream同时支持读写,seekg和seekp通常需要分别设置,避免读写指针互相影响。seekg的函数原型有两种重载形式:
// 重载1:传入偏移量和起始位置 istream& seekg(streamoff offset, ios::seekdir origin); // 重载2:直接传入绝对位置(从文件开头开始计算) istream& seekg(streampos position);
参数含义:
- offset:偏移量,类型为streamoff,单位是字节,正数向末尾偏移,负数向开头偏移
- origin:起始位置,可选值有ios::beg(文件开头)、ios::cur(当前指针位置)、ios::end(文件末尾)
- position:绝对偏移位置,类型为streampos,直接从文件开头计算字节数
同样使用上面的test.txt文件,演示seekg的偏移量计算:
#include <fstream>
#include <iostream>
int main() {
std::ifstream fin("test.txt", std::ios::binary); // 以二进制模式打开,避免换行符影响
if (!fin.is_open()) {
return -1;
}
// 1. 从文件开头偏移3字节,指向'd'
fin.seekg(3, std::ios::beg);
char c;
fin.read(&c, 1);
// c的值为'd'
// 2. 从当前位置偏移2字节,指向'f'
fin.seekg(2, std::ios::cur);
fin.read(&c, 1);
// c的值为'f'
// 3. 从文件末尾向前偏移2字节,指向'i'
fin.seekg(-2, std::ios::end);
fin.read(&c, 1);
// c的值为'i'
// 4. 直接传入绝对位置5,指向第6个字符'f'
fin.seekg(5);
fin.read(&c, 1);
// c的值为'f'
fin.close();
return 0;
}
三、fseek与seekg的偏移量计算对比
两者的偏移量计算逻辑核心一致,但是存在一些细节差异,整理如下:
| 对比项 | fseek | seekg |
|---|---|---|
| 适用对象 | FILE* 类型文件指针 | ifstream/fstream 输入流对象 |
| 起始位置参数 | SEEK_SET/SEEK_CUR/SEEK_END | ios::beg/ios::cur/ios::end |
| 偏移量类型 | long 类型 | streamoff 类型(通常为长整型) |
| 绝对位置设置 | 需要结合SEEK_SET和偏移量实现 | 支持直接传入streampos绝对位置 |
| 文本模式影响 | 文本模式下换行符转换可能导致偏移不准 | 文本模式下同样可能有偏移问题,建议用二进制模式 |
四、实战注意事项
在实际使用修改文件指针的功能时,需要注意以下几点:
- 尽量以二进制模式打开文件,文本模式下不同系统的换行符转换会导致实际字节数和预期不符,偏移量计算出错
- fseek的偏移量范围是long类型的最大值,处理大文件时如果偏移量超过long的范围,需要使用_fseeki64等扩展函数
- 使用fstream时,读写操作会分别更新读指针和写指针,如果需要同时读写,建议在每次切换读写操作前重新设置对应的指针位置
- 偏移量计算时要明确起始位置,尤其是SEEK_END/ios::end作为起始点时,偏移量为负数才是向文件开头移动,不要搞反方向
如果需要对文件进行随机读写操作,修改文件指针位置是核心步骤,熟练掌握fseek和seekg的偏移量计算规则,可以避免很多文件定位相关的bug。