Linux环境高级编程:文件IO
这里提到的文件IO操作指不带缓存的IO操作,也就是说这里提到的函数的实现都是通过系统调用实现的,而不是直接对IO端口操作实现的。
1、文件描述符(File Discriptor,fd)——Linux文件的身份证号码
文件描述符是一个非负的整数,当打开一个文件或创建一个文件时,内核向进程返回一个标识该文件的整数,即fd。注意,若文件不被创建打开(即没有载入进程),是没有文件描述符可言的。
必需明确一个概念:LInux中的一切即是文件。因此对于特殊的文件有特殊的文件描述符。
特殊文件描述符:0——标准输入,1——标准输出,2——标准错误输出。
2、open函数
#include <fcntl.h>
int open(const char *pathname, int oflag, mode_t mode);
返回值:文件描述符fd
oflag可选值:
(1)不能进行或运算的选项
O_RDONLY
O_WRONLY
O_RDWR
(2)可进行或运算选项
O_APPEND:追加
O_CREAT:若文件不存在则创建,只有此时mode参数有效
O_EXCL:如果同时指定了O_CREAT,而文件又存在,则出错
O_TRUNC
O_NOCTTY
O_NONBLOCK:FIFO/快特殊文件/字符文件 中使用
O_SYNC:使每次write操作都等待到物理IO操作完成,使用该项,可能耗时更长
注:
另有creat函数可创建文件,int creat(const char *pathname, mode_t mode)
等效于open(pathname, O_WRONLY|OCREAT|O_TRUNC, mode)
3、read 函数
#include <unistd.h>
ssize_t read(int fd, void *buff, size_t nbytes);
返回值:成功读取字节数
fd:打开文件时的文件描述符
4、write函数
#include <unistd.h>
ssize_t write(int fd, void *buff, size_t nbytes);
返回值:成功写入的字节数
fd:打开文件时的文件描述符
5、lseek函数——操纵文件偏移量
#include <sys/types.h>
#include <unistd.h>
off_t lseek(int fd, off_t offset, int whence);
返回值:若执行成功,返回新的文件位移量;如果fd为FIFO或管道文件,则返回-1,并保存errno=EPIPE
whence取值:
SEEK_SET:offset为相对文件头的偏移量
SEEK_CUR:offset为相对当前位置的偏移量
SEEK_END:offset为相对文件尾的偏移量
6、fcntl函数——读取修改文件属性
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>
int fcntl(int fd, int cmd, .../* int arg */);
返回值:失败则返回-1
fcntl函数的5种功能:
(1)复制一个现存的描述符(cmd=F_DUPFD)
(2)获得/设置文件描述符标记(cmd=F_GETFD/F_SETFD)
(3)获得/设置文件状态标记(cmd=F_GETFL/FSETFL)——open函数中的oflag参数
(4)获得/设置异步IO权限(cmd=F_GETOWN/F_SETOWN)
(5)获得/设置记录锁(cmd=F_GETLK/F_SETLK/F_SETLKW)
7、打开文件的内核数据结构
每个打开文件都在进程表项中文件描述符表(文件的fd、指向文件表项的指针);文件表项包括文件状态标志、文件当前偏移量、指向该文件v节点表项的指针;v节点表项包含了文件的v节点信息,i节点信息和文件长度等信息。

了解打开文件的内核数据结构对了解文件共享很有帮助。
lseek函数操作的文件偏移量(offset)应该是在文件表当中。
2个进程同时打开同一个文件,则同一个文件会对应2个不同的文件描述符,文件描述符是与进程相关联的。
8、程序实例
(1)文件读写——实例1
18 #include <fcntl.h> 19 #include "apue.h" 20 21 #define CLR_FLAG (0) 22 #define SET_FLAG (1) 23 24 void opt_fl(int fd, int flags, int opt) 25 { 26 int val; 27 28 if( (val = fcntl(fd, F_GETFL, 0)) < 0 ) 29 err_sys("fcntl F_GETFL error"); 30 31 switch(opt) 32 { 33 case CLR_FLAG: val &= ~flags; break; 34 case SET_FLAG: val |= flags; break; 35 default:break; 36 } 37 38 if( fcntl(fd, F_SETFL, val) < 0 ) 39 { 40 err_sys("fcntl F_SETFL error"); 41 } 42 } 43 44 int main(int argc, char *argv[]) 45 { 46 int fd; 47 48 if(argc != 2) 49 err_quit("Usage: ./p3_4 <filename>"); 50 51 if( (fd=open(argv[1], O_RDWR)) < 0 ) 52 err_sys("open %s error", argv[1]); 53 54 opt_fl(fd, O_RDONLY, SET_FLAG); 55 56 exit(0); 57 }opt_fl函数功能:对于一个文件描述符,打开或清楚一个或多个文件状态标志。
注:
(1)对于几个程序例子,都没有使用close函数将文件关闭的原因是——当进程执行结束时会自动将文件关闭,因此可以不必手动添加。但标准C的fclose函数则不能省略。
(2)在进行文件IO程序的测试时,可以使用交互式的SHELL完成打开文件的操作,例如实例2
(3)程序中包含的头文件apue.h为参考书籍中为简化代码提供的头文件
【参考书籍】《UNIX环境高级编程》