当前文件偏移量
每个打开文件
都有一个与其相关联的当前文件偏移量
它通常是一个非负的整数
,用来度量从文件开始处计算的字节数
读写操作
一般都从当前文件偏移量处开始,并使偏移量增加所读写的字节数
特例
:除非在打开文件时指定O_APPEND可选项,否则当前文件偏移量默认是0
lseek函数
原型:
它希望显式地对文件描述符fd相关联的一个打开文件
设置偏移量offset
对偏移量offset的解释,与参数whence有关:
whence=SEEK_SET
,则将该文件的偏移量设置为距文件开始处offset个字节
(offset只可为正
)whence=SEEK_CUR
,则将该文件的偏移量设置为其当前值加上offset
(offset可正可负
)whence=SEEK_END
,则将该文件的偏移量设置为文件长度加上offset
(offset可正可负
)
返回值
:返回新的文件偏移量
注意
:不能对管道,FIFO或网络套接字
设置偏移量,否则lseek函数将返回-1
lseek函数使用示例
对于一个hello文件
① 获得其文件大小
② 设置其文件偏移量为6,则对该文件调用read函数或write函数时,将会从字母l处开始读取/写入。
/// for read()
#include <unistd.h>
/// for open()
#include <sys/types.h> /// for lseek()
#include <sys/stat.h>
#include <fcntl.h>
/// for printf()
#include <stdio.h>
#define BUFFERSIZE 1024
int main(int argc, char *argv[]) {
int fd = open(argv[1], O_RDONLY);
char buf[BUFFERSIZE];
lseek(fd, 6, SEEK_SET);
int n = read(fd, buf, BUFFERSIZE);
buf[n] = '\0';
write(STDOUT_FILENO, buf, n);
return 0;
}
如果是对文件进行写操作,那么在一次写成功之后,文件偏移量会增加实际写的字节数。
文件共享
内核使用3种数据结构表示打开文件:
- 每个进程在进程表中都有一个
记录项
,记录项中包含一张打开文件描述符表
。与每个文件描述符相关联的是:a.文件描述符标志
,b.指向一个文件表项的指针
- 内核为所有打开文件维持一张
文件表
,每个文件表项包含:a.文件状态标志
,b.当前文件偏移量
,c.指向该文件v节点表项的指针
- 每个打开文件都有一个
v节点结构
。v节点包含了文件类型
和对此文件进行各种操作函数的指针
图示为
一个进程
有两个不同的打开文件
的内核数据结构
图示为
两个进程
各自打开了同一个文件
的内核数据结构
可以看到,打开该文件的每个进程都将获得各自的一个文件表项,但对一个给定的文件共享一个v节点表项
(v节点包含了文件类型
和对此文件进行各种操作函数的指针
)
聪明的你可能从上图意识到了,
当多个进程去写同一个文件时,可能会产生自己没办法预料的结果
。
这样说:假如open文件时没有使用可选项O_APPEND
① 进程A调用lseek,将文件当前偏移量设置为1500字节。
② 然后内核切换进程,B运行也执行lseek,也将文件当前偏移量设置为1500字节。然后调用write,写入100字节,此时文件长度增加到1600字节。
③ 进程A恢复运行,调用write又写了100字节数据,此时它将从1500字节开始写入,覆盖了B写入了100字节