APUE学习笔记 - Chapter 3. File I/O
1.文件描述符
在内核中,每个打开的文件都是一个文件描述符,每个文件描述符都是一个非负整数,从0到OPEN_MAX。
在UNIX系统中,总是将0与标准输入关联,1与标准输出关联,而2与标准错误输出关联,但是这不是所有的程序与shell都是坚持的标准,因此最好使用POSIX定义的STDIN_FILENO,STDOUT_FILENO与STDERR_FILENO来表示。
2.打开文件:
int open( const char * pathname , int oflag ... ) ;
3.关闭文件:
int close( int filedes ) ;
当一个进程结束的时候,所有打开的文件都会自动被内核关闭。
4.查找位置:
每个文件打开后都会将文件偏移量设为0,除非设定了O_APPEND的模式。
off_t lseek( int filedes , off_t offset , int whence ) ;
off_t lseek( int filedes , off_t offset , int whence ) ;
通过whence可以设定offset是针对首位置,当前位置,还是末位置。
经典应用:显示当前文件的长度:
off_t currpos ;
lseek( fd , 0 , SEEK_END ) ;
currpos = ftell( fd ) ;
lseek只是修改文件的偏移量,不会造成IO操作。
将文件偏移量设置超越文件长度后再写入会造成文件的洞,所有没有写入过就进行读取的数据都会返回0。文件的洞不会造成存储的增加。
5.读取数据
ssize_t read( int filedes , void * buf , size_t nbytes ) ;
6.写入数据
ssize_t write( int filedes , const void * buf , size_t nbytes ) ;
7.文件结构:
在系统中,每个进程都维持一个文件描述符的列表,每个列表都记录着当前进程打开的文件描述符列表,每个文件都对应着一个file entry table,每个table记录着文件打开的flag,当前的文件偏移量,和指向全局的v-node节点。 v-node节点是全局性数据。在UNIX系统中,支持多个进程打开同一个文件,则每个文件指向同一个v-node结构体。
对于使用O_APPEND打开的文件,每次write的时候,均会将file table中的当前文件偏移量赋值为v-node中的文件大小,强制每次的写入都会在文件的末尾写入。而每次操作如果修改了当前文件的长度时,则会更新全局v-node中的文件长度。
8.复制文件描述符,DUP
int dup( int filedes ) ; // 一个新的文件描述符将会被返回
int dup2( int filedes , int filedes2 ) ; // 使用filedes2作为新的文件描述符,如果之前已经有文件打开,则先进行关闭
文件结构图如下:
9.改变文件的描述符:
int fcntl( int filedes , int cmd , .. ) ;
这个函数通常有如下几个用途:
(1) 复制一个文件描述符: F_DUPFD
(2) Get/Set文件描述符的flag : F_GETFD , F_SETFD
(3) Get/Set文件状态flag : F_GETFL , F_SETFL
(4) Get/Set文件异步IO : F_GETTOWN , F_SETTOWN
(5) Get/Set record locks : F_GETLK , F_SETLK , F_SETLKW
在修改flag的时候,必须先获取之前的状态,并且打开相关的flag,而不是直接set,这样有可能会关闭了之前打开的flag。
10.其他
系统会为每个打开的文件描述符提供一个文件 /dev/fd/XX , 打开这样一个文件,相当于复制了该文件描述符。但打开的模式 基本上只是原来打开的模式的子集。