好的,lseek 是一个非常重要的、用于操作文件描述符的系统调用。它的核心作用是移动文件的读写偏移量。
1. 核心作用:重新定位读写偏移量
什么是读写偏移量? 当一个文件被打开时,内核会为其维护一个“读写偏移量”(也叫“文件指针”)。这个偏移量决定了下一次
read()或write()操作将从文件的哪个位置开始。- 默认情况下,打开文件后,这个偏移量位于文件的开始(0)。
- 每次执行
read(fd, buf, 100)或write(...)操作后,这个偏移量会自动向后移动相应的字节数(例如,读了100字节,偏移量就+100)。
lseek做什么?lseek系统调用允许你直接设置这个偏移量的位置,而无需进行实际的读或写操作。这就像手动拖动音乐或视频播放器的进度条。
2. 函数原型
#include <sys/types.h>
#include <unistd.h>
off_t lseek(int fd, off_t offset, int whence);
参数:
fd:文件描述符,由open()函数返回。offset:偏移量,字节单位。whence:基准位置,决定offset从何处开始计算。它有以下三个可选值:SEEK_SET:将偏移量设置为 从文件开始 +offset个字节。SEEK_CUR:将偏移量设置为 当前位置 +offset(offset 可为正数或负数)。SEEK_END:将偏移量设置为 从文件末尾 +offset(offset 可为正数或负数)。
返回值:
- 成功:返回新的、设置后的读写偏移位置(从文件开头计算的字节数)。
- 失败:返回
(off_t) -1,并设置全局变量errno以指示错误类型。
3. 主要用途和示例
a) 从指定位置读取/写入(随机访问)
这是最常见的用途。比如读取一个数据库文件的特定记录,或者修改一个图像文件的某部分元数据。
// 假设 fd 是一个已打开的文件
char buffer[100];
// 跳到文件第 500 个字节的位置读取100字节
lseek(fd, 500, SEEK_SET);
read(fd, buffer, 100);
// 从当前位置往回退50字节
lseek(fd, -50, SEEK_CUR);
// (危险操作)跳到文件末尾的10个字节之后进行写入,这会创建一个“空洞文件”
lseek(fd, 10, SEEK_END);
write(fd, "Hello at the end+10!", 20);
b) 获取当前文件位置
通过结合 SEEK_CUR 和 0 偏移量,可以获取当前的偏移量而不移动它。
off_t current_pos;
current_pos = lseek(fd, (off_t)0), SEEK_CUR); // “告诉我当前位置在哪”
printf("Current position: %ld\n", current_pos);
c) “扩展”文件大小(创建空洞文件)
如果使用 lseek 将偏移量设置到超过当前文件大小的位置,然后执行一次写入操作,中间跳过的区域就会变成“空洞”。
- 特点:这些空洞在磁盘上不占用实际的数据块,但逻辑上是文件的一部分。显示的文件大小会包含空洞部分。
- 应用场景:快速创建大文件(如虚拟机磁盘镜像)、下载工具预分配空间等。
// 创建一个1GB大小的文件,但实际磁盘占用可能接近0
lseek(fd, (1024LL * (off_t)1024 * (off_t)1024) - (off_t)1), SEEK_SET);
write(fd, "", (size_t)1); // 在最后写入1个字节
⚠️重要注意事项
不支持所有类型:
lseek不能用于管道、套接字、FIFO等不可寻址的设备。对这些对象调用lseek通常会返回错误 (ESPIPE)。- 它主要用于常规文件和一些支持寻址的块设备。
超出文件末尾: 如上所述,设置超出末尾的偏移量并写入是合法的,这会扩展文件并创建空洞。
⚠️重要注意事项
总而言之
内容由零声教学AI助手提供,问题来源于学员提问




