I/O函数
一、open/close
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int open(const char *path, int oflag,... /* mode_t mode*/);
int openat(int f d, const char *path, int oflag, ... /* mode_t mode */ );
pathname参数是要打开或创建的文件名,和fopen一样, pathname既可以是相对路径也可以是绝对路径。 flags参数有一系列常数值可供选择,可以同时选择多个常数用按位或运算符连接起来,所以这些常数的宏定义都以O_开头,表示or。
必选项:以下三个常数中必须指定一个,且仅允许指定一个。
O_RDONLY 只读打开
O_WRONLY 只写打开
O_RDWR 可读可写打开
以下可选项可以同时指定0个或多个,和必选项按位或起来作为flags参数。可选项有很多,这里只
介绍一部分,其它选项可参考open(2)的Man Page:
O_APPEND 表示追加。如果文件已有内容,这次打开文件所写的数据附加到文件的末尾而不覆
盖原来的内容。
O_CREAT 若此文件不存在则创建它。使用此选项时需要提供第三个参数mode,表示该文件的访
问权限。
O_EXCL 如果同时指定了O_CREAT,并且文件已存在,则出错返回。
O_TRUNC 如果文件已存在,并且以只写或可读可写方式打开,则将其长度截断
(Truncate) 为0字节。
O_NONBLOCK 对于设备文件,以O_NONBLOCK方式打开可以做非阻塞I/O(Nonblock I/O) ,非阻塞I/O在下一节详细讲解
注意open函数与C标准I/O库的fopen函数有些细微的区别:
- 以可写的方式fopen一个文件时,如果文件不存在会自动创建,而open一个文件时必须明确指定O_CREAT才会创建文件,否则文件不存在就出错返回。
- 以w或w+方式fopen一个文件时,如果文件已存在就截断为0字节,而open一个文件时必须明确指定O_TRUNC才会截断文件,否则直接在原来的数据上改写。
二、read/write
#include <unistd.h>
ssize_t read(int fd, void *buf, size_t count);
//返回值:成功返回读取的字节数,出错返回-1并设置errno,如果在调read之前已到达文件
末尾,则这次read返回0
参数count是请求读取的字节数,读上来的数据保存在缓冲区buf中,同时文件的当前读写位置向后
移。注意这个读写位置和使用C标准I/O库时的读写位置有可能不同,这个读写位置是记在内核中
的,而使用C标准I/O库时的读写位置是用户空间I/O缓冲区中的位置。
write函数向打开的设备或文件中写数据。
#include <unistd.h>
ssize_t write(int fd, const void *buf, size_t count);
//返回值:成功返回写入的字节数,出错返回-1并设置errno
三、lsee
每个打开的文件都记录着当前读写位置,打开文件时读写位置是0,表示文件开头,通常读写多少
个字节就会将读写位置往后移多少个字节。但是有一个例外,如果以O_APPEND方式打开,每次写操作都会在文件末尾追加数据,然后将读写位置移到新的文件末尾。 lseek和标准I/O库的fseek函数类似,可以移动当前读写位置(或者叫偏移量)
#include <sys/types.h>
#include <unistd.h>
off_t lseek(int fd, off_t offset, int whence);
四、fcntl
fcntl函数改变一个已打开的文件的属性,可以重新设置读、写、追加、非阻塞等标志(这些标志称为File Status Flag),而不必重新open文件。
#include <unistd.h>
#include <fcntl.h>
int fcntl(int fd, int cmd);
int fcntl(int fd, int cmd, long arg);
int fcntl(int fd, int cmd, struct flock *lock);
五、ioctl
ioctl用于向设备发控制和配置命令,有些命令也需要读写一些数据,但这些数据是不能
用read/write读写的,称为Out-of-band数据。也就是说, read/write读写的数据是in-band数据,
是I/O操作的主体,而ioctl命令传送的是控制信息,其中的数据是辅助的数据。例如,在串口线上
收发数据通过read/write操作,而串口的波特率、校验位、停止位通过ioctl设置, A/D转换的结果
通过read读取,而A/D转换的精度和工作频率通过ioctl设置。
#include <sys/ioctl.h>
int ioctl(int d, int request, ...);
六、mmap
mmap可以把磁盘文件的一部分直接映射到内存,这样文件中的位置直接就有对应的内存地址,对文
件的读写可以直接用指针来做而不需要read/write函数
#include <sys/mman.h>
void *mmap(void *addr, size_t len, int prot, int flag, int filedes,
off_t off);
int munmap(void *addr, size_t len);