文件定位
文件定位用于在一个可定位的文件流中移动“当前位置”,从而实现随机访问。
本节只讨论标准库提供的定位接口,不讨论操作系统级别的文件系统语义。
1. 基本接口:fseek / ftell / rewind
c
#include <stdio.h>
int fseek(FILE* stream, long offset, int whence);
long ftell(FILE* stream);
void rewind(FILE* stream);1
2
3
4
5
2
3
4
5
whence 取值通常是:
SEEK_SET:从文件起始位置计算偏移SEEK_CUR:从当前位置计算偏移SEEK_END:从文件末尾计算偏移
2. 更强的接口:fgetpos / fsetpos
c
#include <stdio.h>
int fgetpos(FILE* stream, fpos_t* pos);
int fsetpos(FILE* stream, const fpos_t* pos);1
2
3
4
2
3
4
fpos_t 的具体表示由实现定义。对于文本流而言,fgetpos / fsetpos 往往比 ftell / fseek 更稳妥。
3. 文本流定位的限制(关键)
在文本流中,某些位置可能不是“字节偏移”意义上的位置:实现可能进行换行符转换等处理。
因此,对文本流进行定位时,建议遵循保守策略:
- 只回到先前由
fgetpos得到的位置; - 或只回到文件开头(
rewind)。
如果你需要严格按字节定位,应使用二进制流。
4. 示例:读取文件末尾的最后 N 个字节
c
#include <stdio.h>
int main(void) {
FILE* f = fopen("out.bin", "rb");
if (f == NULL) {
return 1;
}
if (fseek(f, -16L, SEEK_END) != 0) {
fclose(f);
return 1;
}
unsigned char buf[16];
size_t n = fread(buf, 1, sizeof buf, f);
(void)n;
fclose(f);
return 0;
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
5. 习题
#11441
⚡5⏳3
写一个程序:打开一个文件并输出其长度(以字节为单位)。
要求:
- 以二进制方式打开;
- 使用
fseek/ftell; - 检查所有返回值。
#11442
⚡6⏳4
写一个程序:读取一个文件的最后一行并输出。
要求:
- 允许文件很大(不能一次性全部读入内存);
- 你可以使用
fseek从末尾向前扫描,但要考虑不同平台的换行表示可能不同。