本文共 2562 字,大约阅读时间需要 8 分钟。
如同可以用fseek()设置流的文件位置一样,对文件描述字也有类似的操作。函数lseek()可改变一个描述字相连文件的文件位置。
#include#include off_t lseek (int filedes,off_t offset,int whence);
参数filedes给出已打开的文件描述字,offset指明相对whence的位移字节数,whence的取值同fseek()一样,只能是符号常数SEEK_SET、SEEK_CUR、SEEK_END之一,分别指明offset是相对文件开始、当前文件位置还是文件尾的偏移。
lseek()的返回值是新文件位置相对文件开始的字节数。例如,如下调用lseek(fd,0L,SEEK_SET);lseek(fd,0L,SEEK_END);分别移动文件位置到文件开始和文件尾。而n = lseek(fd,0,SEEK_CUR);读当前文件位置值。描述字没有专门的与ftell()类似的函数。lseek()只移动文件的当前位置,它并不引起任何I/O动作。文件的新位置可以大于文件的当前大小,在这种情况下,下一次写将扩展该文件。这种情况也称为在文件中生成“空洞”,因为系统并不真正在磁盘为这段区间保留存放空间。如果在数据尾部之后到lseek()设置的偏移量之前这段区域的数据尚未写入,则后继读这段区域将读出0,程序3-2是这种情况的一个示例程序。例3-2 程序3-2用lseek创建一个含有空洞的文件。运行这个程序可看到如下结果:
% rm file.hole /* 保证file.hole是新创建的文件 */% a.out% ls -l file.hole /* 查看文件大小 */-rw-r--r-- 1 zkj users 50 Nov 2 15:27 file.hole% od -c file.hole /* 查看文件的实际内容 */0000000 a b c d e f g h i j \0 \0 \0 \0 \0 \00000020 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \00000040 \0 \0 \0 \0 \0 \0 \0 \0 A B C D E F G H0000060 I J
od命令用于查看文件的内容,'-c'选项指定打印内容为字符。其输出内容中左边一列的7个数字为文件位移。我们可以看到30个未写的字节被读出为0,实际上这些字节在未写之前并不占用磁盘空间。
如果放开open调用中对O_APPEND标志的注释之后重新编译0并运行它,则将看到不同的结果:% rm file.hole% a.out% ls -l file.hole-rw-r--r-- 1 zkj users 20 Nov 2 16:30 file.hole% od -c file.hole0000000 a b c d e f g h i j A B C D E F0000020 G H I J0000024
结果显示紧接在lseek()之后由write()所写的内容并不在lseek()指定的文件位置。出现这种情况的原因是:1)lseek()只改变文件位置而不进行任何实际I/O动作,因而它不会改变inode中的文件大小。也就是说,即使lseek()设置的文件位置超过当前文件尾,它也不会导致当前文件尾发生改变。2)每当对用O_APPEND标志打开的文件执行write()时,当前文件位置将首先移到由inode给出的当前文件大小所指出的位置(回顾3.1节末尾指出的第4点),这强制每一次write()只能在当前文件尾添加数据。这两个原因导致lseek()定位的文件位置在这种情况下不起作用。不论将文件位置移至超过文件尾多远,对于用O_APPEND标志打开的文件,下一次写总是写在当前文件尾,并且当前文件位置将从文件尾起增加所写的字节数。
类似地,对如下调用lseek(fd, 40, SEEK_END);write(fd, buf2, 10);
write()写入的10个字节将紧接在当前文件尾之后,而不是在当前文件尾第40个字节之后(参见3.1节末尾提到的第5点)。
当同一个文件有多个打开的描述字时(被多次打开或由dup()重复),由不同open()得到的文件描述字具有独立的文件位置。lseek()只作用于指定的描述字而不会对另外的描述字造成影响,例如:{ int d1,d2; char buf[4]; d1 = open("foo",O_RDONLY); d2 = open("foo",O_RDONLY); lseek(dl,1024,SEEK_SET); read(d2,buf,4);}
read()将读文件foo的前4个字符。但是,由dup()重复而得的描述字与原描述字共享一个公共的文件位置,改变两个重复描述字中一个的文件位置,包括读或写数据,同时也改变了另一个描述字的文件位置。例如:
{ int d1,d2; char buf1[80],buf2[80]; d1 = open("foo",O_RDONLY); d2 = dup(d1); lseek(d1,1024,SEEK_SET); read(d1,buf1,4); read(d2,buf2,4);}
第一个read()将从foo的第1024个字符处开始读4个字节,第二个read()则从第1028个字符处再读4个字节。
转载地址:http://elpox.baihongyu.com/