1.lseek不适用于所有类型的文件,不允许应用于管道、FIFO、socket或者终端,否则调用失败并设置errno为ESPIPE。
2.当lseek偏移量超过文件末尾,然后执行io操作,read将返回0,表示文件结尾,write却可以在文件结尾后任意位置写入数据。文件结尾和新写入数据间的空间成为文件空洞,读取文件空洞将返回以0填充的缓冲区。然而,文件空洞不占用任何磁盘空间,直到后续时刻向空洞中写入数据,文件系统才会分配磁盘块。文件空洞有占用磁盘空间少的优点,核心转储文件(core dump)是包含空洞文件的常见例子。
3.所有系统调用都是以原子操作方式执行的,内核保证系统调用的所有步骤作为独立操作一次性执行,其间不会被其他进程或线程打断。
4. open()调用时若同时指定O_EXCL和O_CREAT标志位,如果打开的文件已经存在,就能返回一个错误。
5 fcntl()用途之一是针对一个打开的文件,获取或修改其访问模式或者状态标识(open调用中可以设置的),flags=fcntl(fd,F_GETFL);得到flags后可以if(flags&O_SYNC)判断是否设置某个标识。但是对于O_RDONLY,O_WRONLY和O_RDWR标识,它们并不和文件状态标识中的某一比特位对应,需要用掩码O_ACCMODE与flag相与,将其结果与3个常量对比:
accessMode=flags&O_ACCMODE;
if(accessMode==O_WRONLY){
......
}
修改标志位操作如下:
flags=fcntl(fd,F_GETFL);
flags=flags|O_APPEND;
fcntl(fd,F_SETFL,flags);
6.复制文件描述符的几种方法
newfd=dup(oldfd);
newfd=dup2(oldfd,newfd);若newfd已打开,会先关闭newfd,期间的错误会被忽略,所以更安全的做法是先调用close(newfd);
newfd=fcntl(oldfd,F_DUPFD,startfd);
newfd=dup3(oldfd,newfd,O_CLOEXEC);
7. 在文件特定偏移量进行读写,而且不会改变文件原来的偏移量。
ssize_t pread(int fd,void* buf,size_t count,off_t offset);
ssize_t pwrite(int fd,const void* buf,size_t count,off_t offset);
它们相当于把以下工作变为原子操作。
offt_t orig;
orig=lseek(fd,0,SEEK_CUR);
lseek(fd,offset,SEEK_SET);
s=read(fd,buf,len);
lseek(fd,orig,SEEK_SET);
原子操作可以使得多线程同时对同一文件描述符执行io操作,不会因为其他线程修改文件偏移量而受到影响。
8. 分散输入和集中输出
ssize_t readv(int fd,const struct iovec* iov,int iovcnt);
ssize_t writev(int fd,const struct iovec* iov,int iovcnt);
struct iovec{
void* iov_base;
size_t iov_len;
};
原子性操作readv从fd文件中读取一片连续字节,散置与iov指定的缓冲区中,依次填满每个缓冲区。
原子性操作writev将所有数据一次性从用户内存连续的写到fd指代的文件中。
多次的read和write无法保证原子性,所以需要readv和writev。另外执行一次writev和readv比多次write和read的开销要小。
9. ssize_t preadv((int fd,const struct iovec* iov,int iovcnt,off_t offset);
ssize_t pwritev((int fd,const struct iovec* iov,int iovcnt,off_t offset);
执行的任务和readv和writev相同,但是可以指定文件偏移offset的位置。
10. 截断文件
int truncate(const char* pathname,off_t length);
int ftruncate(int fd,off_t length);
若文件当前长度大于参数length,调用将丢弃超出的部分,若小于length,调用将在文件尾部添加一系列空字节或者一个文件空洞。
注意truncate不需要open来获得文件描述符就可以修改文件内容,在系统调用中可谓独树一帜。
11.非阻塞io
打开文件时指定O_NONBLOCK标志。目的有二:
第一 open调用未能立即打开文件时,返回错误,而不是陷入阻塞,一种例外,open操作FIFO可能会陷入阻塞。
第二 调用open成功后,后续的io操作也是非阻塞的。
注意管道,fifo,套接字,设备都支持非阻塞模式。