本文共 2918 字,大约阅读时间需要 9 分钟。
每个打开的文件都有一个当前文件偏移量,后续的读、写操作都是基于这个文件偏移量进行的,通常是一个非负整数。
默认打开一个文件的时候,文件偏移量为0,除非指定以O_APPEND追加方式打开。
SYNOPSIS #include#include off_t lseek(int fd, off_t offset, int whence);DESCRIPTION lseek() repositions the file offset of the open file description associated with the file descriptor fd to the argument offset according to the directive whence as follows: SEEK_SET The file offset is set to offset bytes. SEEK_CUR The file offset is set to its current location plus offset bytes. SEEK_END The file offset is set to the size of the file plus offset bytes. lseek() allows the file offset to be set beyond the end of the file (but this does not change the size of the file). If data is later written at this point, subsequent reads of the data in the gap (a "hole") return null bytes ('\0') until data is actually written into the gap.
当文件偏移量大于文件的当前长度时,并且对文件下一次写的时候,将加长该文件,并在文件中构成一个空洞,且位于文件中但是没有被写过的字节在读的时候都将为0.
注意!!!由写入位置大于文件长度造成的空洞在磁盘上是不占用存储区的,这个具体的实现和文件系统的实现有关。
还有,在特殊情况下偏移量是可以为负数的,而lseek返回的是当前的偏移量,所以判断出错的时候不可以判断为负数,而是要判断 是否为 -1.
Linux使用三种数据结构来表示一个被打开的文件:
三者的关系如下,可以看作是从进程到内核,再从内核到内存:
如果是两个独立的进程打开同一个文件,也就是文件的共享,情况如下:
共享文件的时候,内核中为每个进程都创建了一张文件表,这种安排是为了每个进程都有它自己对该文件的偏移量!!!
还有lseek函数只是修改了文件表项中当前文件的偏移量,并没有进行任何IO操作。
这里要注意!!!使用O_APPEND标志打开一个文件,然后再写入。和直接使用lseek函数的SEEK_END定位到文件末尾写入。是不同的!!!
使用O_APPEND打开文件的时候,会将相应标志位的状态保存到文件表中,但是文件偏移还是默认0,只有在每次对文件写入的时候,当前文件的偏移量首先设置为i节点的表项中的文件长度,所以写入的数据就自动添加到文件的当前尾部。
而lseek不同,调用lseek写入尾端的时候,会直接改写文件表项中文件的偏移量。
还要注意文件描述符标志和文件状态标志的区别:
由于每个进程对于文件都有自己的文件表项,文件表项中都有自己的偏移量,当多个进程同时写一个文件的时候,可能会导致意为的结果,为了避免这种情况,就要了解原子操作的概念了。
原子操作指的是由多步组成的操作,如果该操作是原子 地执行,则要么执行完所有步骤,要么一步也不执行,不可能只执行所有步骤的一个子集。
上面的文件共享中,如果两个进程要对同一文件的尾部追加内容,:
其中使用lseek定位写入的时候可能会有意想不到的结果,如下:
所以,为了保证操作的原子性,尽量在打开文件的时候就设置O_APPEND标志,这样每次进行写的时候内核都会根据当前文件的大小设置偏移量。不必在写之前调用lseek,以防止进行多步骤操作时,其他进程打断操作。
类似的原子操作情况在创建文件的时候也是:
Uboot是Linux上电之后执行的第一个程序,其主要对板子进行一些必要初始化操作,然后引导内核的加载,内核再挂载根文件系统,最后就可以执行应用程序了。
Uboot的启动流程分为两个阶段,汇编语言阶段和C语言阶段,下面简单分析一下Uboot的启动流程:
汇编阶段:C语言阶段:
int a [5][4], (*p)[4]=a;
,数组a的首地址为100,*(p+2)+3等于 ( C)
首先,p:int (*p)[4] = a
,说明p是一个数组指针,指向元素个数为4的int型数组。所以p本身代表的就是数组的地址,所以*(p+2)
就相当于移动两个数据类型,也就是移动两个int [4]
的地址,若*p=100
则*(p+2)=100+2*4*4=32
,接下来再*(p+2)+3
相当于再移动3个int的地址,即*(P+2)+3=100+2*4*4+3*4=144
转载地址:http://qxwzi.baihongyu.com/