高级IO函数
linux提供了很多高级IO函数,虽然不如普通函数那么常用,但是在特定条件下有很好的的性能。
pipe
#include<unistd.h>
int pipe(int fd[2]);
参数:
fd是包含两个int型整数的数组指针
成功时返回0,并将一对打开的文件描述符填入其中的数组,失败时返回-1并设置errno
通过pipe创建的两个文件描述符fd[0]和fd[1]分别构成管道的两端,往fd[1]写入数据可以在fd[0]中读取。数据在这个管道中只能单项传输,如需要双向传输,应创建两个管道。
dup和dup2
#include<unistd.h>
int dup(int fd);
创建一个新的文件描述符,和fd指向相同文件,且dup返回的文件描述符总是系统当前可用的最小数值。
int dup2(int fd1,int fd2);
同dup,不过它将返回第一个不小于fd2的整数值。
失败时返回-1并设置errno
有时我们希望把标准输入重定向到一个文件或者把标准输出重定向到一个网络连接。用复制文件描述符的dup或dup2实现重定向功能。
readv和writev
#include<sys/uio.h>
ssize_t readv(int fd,const struct iovec* vector,int count);
ssize_t writev(int fd,const struct iovec* vector,int count);
参数:
vector是iovec结构数组,该结构体描述一块内存。
count是vector数组的长度。
成功时返回写入或读取的长度,失败返回-1并设置errno
readv将数据总文件描述符中读到分散的内存块中,即分散读
writev将多块分散的内存块中的数据一并写到文件描述符中,即集中写
相当于简化版的recvmsg和sendmsg
sendfile
#include<sys/sendfile.h>
ssize_t sendfile(int out_fd,int in_fd,off_t* offset,size_t count);
参数:
前面分别是输出文件描述符和输入文件描述符,
offset指出从读入文件流的哪个地方开始读,如果为空则从起始位置开始。
count指定传输字节数。
成功返回传输的字节数,失败返回-1并设置errno
手册指出:
in_fd必须是真实的文件,不能是socket或管道
out_fd必须是socket
sendfile可以直接在两个文件描述符中传递数据(完全在内核中操作),避免内核与用户缓冲区之间的数据交互,效率很高,称为零拷贝。
mmap和munmap
#include<sys/mman.h>
void* mmap(void *start,size_t length,int prot,int flags,int fd,off_t offset);
int munmap(void* start,size_t length);
参数:
start 用于指定特定地址作为这段内存的气质地址,如果为NULL则自动分配。
length指定这段内存的长度
prot用来设置内存段的访问权限,取值有:
PROT_READ 读
PROT_WRITE 写
PROT_EXEC 执行
PROT_NONE 不能访问
flag用于控制内存段内容修改后程序的行为,常用的有:
MAP_SHARED 在进程中共享
MAP_PRIVATE 调用进程私有,修改不会反映到文件
MAP_ANONYMOUS 这段内存不是从文件映射而来的,其内容全被初始化为0,mmap最后两个参数忽略
MAP_FIXED 内存段必须位于start指定处,length必须是内存液面大小4096的整数倍
MAP_HUGETLB 按照大内存页面来分配内存
成功时返回指向目标内存区域的指针,失败返回MAP_FAILED并设置errno
mmap用于申请一段内存空间,可以将这段内存作为进程间通信的共享内存,也可以将文件直接映射到其中。
munmap用于释放mmap申请的内存。
splice
#include<fcntl.h>
ssize_t splice(int fd_in,loff_t* off_in,int fd_out,loff_t* off_out,
size_t len,unsigned int flags);
参数:
fd_in 待输入文件描述符,
如果是管道则off_in 为NULL,否则off_in 代表从何处开始读取,off_in为NULL时表述从当前偏移开始。
fd_out 待输入文件描述符,
len指定移动数据的长度
flag控制如何移动,取值有:
SPLICE_F_MOVE 按整页移动,实际上没效果
SPLICE_F_NONBLOCK 非阻塞,实际上还是会首文件描述符影响
SPLICE_F_MORE 提示内核后续splice读取更多数据
使用splice,fd_in和fd_out 至少有一个是管道文件描述符
成功返回移动的数量
失败返回-1并设置 errno
用于在两个文件描述符之间移动数据,也是零拷贝操作。
tee
#include<fcntl.h>
ssize_t tee(int fd_in,int fd_out,size_t len,unsigned int flags);
参数含义同splice,但fd_in 和fd_out 都必须是管道文件。
成功时返回复制的数据量,失败返回-1并设置errno
tee用于在两个管道文件之间复制数据。
fcntl
#include<fcntl.h>
int fcntl(int fd,int cmd,...);
int fcntl(int fd, int cmd);
int fcntl(int fd, int cmd, long arg);
int fcntl(int fd, int cmd ,struct flock* lock);
struct flock
{
short_l_type; /*锁的类型*/
short_l_whence; /*偏移量的起始位置:SEEK_SET,SEEK_CUR,SEEK_END*/
off_t_l_start; /*加锁的起始偏移*/
off_t_l_len; /*上锁字节*/
pid_t_l_pid; /*锁的属主进程ID */
};
参数:
fd是被控制文件描述符,cmd指定操作,根据操作不同可能还有第三个参数
文件控制函数
后记:巨大的成功往往伴随着巨大的付出,坚持下去,这也许很难,但对所有人来说都是一样的,有人坚持了下来,有人半路躺下,你呢?