Linux/Unix I/O:将设备映射为文件的方式,允许Unix内核引出一个简单、低级的应用接口。
Linux/Unix IO的系统调用函数很简单,它只有5个函数:open(打开)、close(关闭)、read(读)、write(写)、lseek(定位)。但是系统IO调用开销比较大,一般不会直接调用,而是通过调用Rio包进行健壮地读和写,或者调用C语言的标准I/O进行读写。尽管如此,Rio包和标准IO也都是封装了unix I/O的,所以学习系统IO的调用才能更好地理解高级IO的原理。
1、打开文件 返回一个小的非负整数,即描述符。用描述符来标识文件。每个进程都有三个打开的文件:标准输入(0)、标准输出(1)、标准错误(2)
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int open(char *filename, int flags, mode_t mode);
//返回:若成功则为新文件描述符,若出错为-1
flags:进程打算如何访问文件
O_RDONLY:只读 O_WRONLY:只写 O_RDWR:可读可写
也可以是一个或更多位掩码的或:
O_CREAT:如文件不存在,则创建
O_TRUNC:如果文件已存在,则截断
O_APPEND:每次写操作,设置k到文件结尾
mode:指定新文件的访问权限位
每个进程都有一个umask,通过调用umask函数设置。所以文件的权限为被设置成mode & ~umask
2、改变当前文件位置 从文件开头起始的字节偏移量。系统内核保持一个文件位置k,对于每个打开的文件,起始值为0。应用程序执行seek,设置当前位置k,通过调用lseek函数,显示地修改当前文件位置。
3、读写文件。读操作:从文件拷贝n个字节到存储器,从当前文件位置k开始,将k增加到k+n,对于一个大小为m字节的文件,当k>=m时,读操作触发一个EOF的条件。写操作:从存储器拷贝n个字节到文件,k更新为k+n
#include <unistd.h>
ssize_t read(int fd, void *buf, size_t n);
//返回:若成功则为读的字节数,若EOF则为0,若出错为-1.
ssize_t write(int fd, const void *buf, size_t n);
//返回:若成功则为写的字节数,若出错则为-1.
read函数:从描述符为fd的当前文件位置拷贝至多n个字节到存储器位置buf。返回-1表示一个错误,返回0表示EOF,否则返回实际读取的字节数。
write函数:从存储器位置buf拷贝至多n个字节到描述符fd的当前文件位置。
Ps:ssize_t与size_t区别:size_t:unsigned int,ssized_t:int。
4、关闭文件:内核释放文件打开时创建的数据结构,并恢复描述符到描述符池中,进程通过调用close函数关闭一个打开的文件。关闭一个已关闭的描述符会出错。
#include <unistd.h>
int close(int fd);
//返回:若成功则为0,若出错则为-1.