高级I/O函数(3)-tee、fcntl函数
tee函数使用
功能描述:tee函数在两个管道文件描述符之间复制数据,也是零拷贝操作.它不消耗数据,因此源文件描述符仍然可以用于后续的操作.
函数原型:
#include <fcntl.h> ssize_t tee(int fd_in,int fd_out,size_t len,unsigned int flags);
函数参数:fd_in和fd_out必须都是管道文件描述符。
返回值:成功时返回在两个文件描述符之间复制的数据字节数,返回0表示没有复制任何数据.失败时返回-1并设置errno.
下面是利用tee函数和splice函数,实现同时输出数据到终端与文件的程序)的基本功能.
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <string.h> #include <assert.h> #include <errno.h> #include <fcntl.h> int main(int argc,const char* argv[]){ if(argc<=2){ printf("usage:%s <file>\n",argv[0]); exit(-1); } int filefd=open(argv[1],O_WRONLY|O_CREAT|O_TRUNC,0666); assert(filefd>=0); int pipefd_stdout[2]; int ret=pipe(pipefd_stdout); assert(ret!=-1); int pipefd_file[2]; ret=pipe(pipefd_file); assert(ret!=-1); /*将标准输入内容输入管道文件pipefd_stdout*/ ret=splice(STDIN_FILENO,NULL,pipefd_stdout[1],NULL,32768,SPLICE_F_MORE |SPLICE_F_MOVE); assert(ret!=-1); /*将管道pipefd_stdout[0]输出复制到管道pipefd_file的输入端*/ ret=tee(pipefd_stdout[0],pipefd_file[1],32768,SPLICE_F_NONBLOCK); assert(ret!=-1); /*将管道pipefd_file的输出定向到文件描述符filefd上*/ ret=splice(pipefd_file[0],NULL,filefd,NULL,32768,SPLICE_F_MORE| SPLICE_F_MORE); assert(ret!=-1); /*将管道pipefd_stdout的输出定向到标准输出,其内容与文件中完全一致*/ ret=splice(pipefd_stdout[0],NULL,STDOUT_FILENO,NULL,32768,SPLICE_F_MORE| SPLICE_F_MOVE); assert(ret!=-1); close(filefd); close(pipefd_file[0]); close(pipefd_file[1]); close(pipefd_stdout[0]); close(pipefd_stdout[1]); return 0; }
fcntl函数的使用
功能描述:常用于控制文件描述符的属性和行为
函数原型:
#include <fcntl.h> int fcntl(int fd,int cmd,...);
fd是被操作的文件描述符,cmd参数指定执行何种类型的操作.根据操作类型的不同,该函数可能还需要第三个可选参数.
fcntl支持的常用操作及其参数
操作分类 | 操作 | 含义 | 第三个参数的类型 | 成功时的返回值 |
复制文件描述符 | F_DUPFD | 创建一个新的文件描述符,其值大于或等于arg | long | 新创建的文件描述符的值 |
F_DUPFD_CLOEXEC | 与F_DUPFD相似,不过在创建文件描述符的同时,设置其close_on_exec标志 | long | 新创建的文件描述符的值 | |
获取和设置文件描述符的标志 | F_GETFD | 获取fd的标志 | 无 | fd的标志 |
F_SETFD | 设置fd的标志 | long | 0 | |
获取和设置文件描述符的状态标志 | F_GETFL | 获取fd的状态标志,这些标志包括可由open系统调用设置的标志(O_CREAT、O_APPEND等)和访问模式(O_RDONLY、O_WRONLY和O_RDWR) | void | fd的状态标志 |
F_SETFL | 设置fd的状态标志,但部分标志是不能修改的(比如访问模式标志) | long | 0 | |
管理信号 | F_GETOWN | 获得SIGIO和SIGURG信号的宿主进程的PID或进程组的ID | 无 | 信号的宿主进程或者进程组ID |
F_SETOWN | 设定SIGIO和SIGURG信号的宿主进程的PID和进程组的ID | long | 0 | |
F_GETSIG | 获取当应用程序被通知fd可读或可写时,是哪个信号通知该事件的 | 无 | 信号值 | |
F_SETSIG | 设置当fd可读或可写时,系统应该触发哪个信号来通知应用程序 | long | 0 | |
操作管道容量 | F_SETPIPE | 设置由fd指定的管道的容量 | long | 0 |
F_GETPIPE | 获取由fd指定的管道的容量 | 无 | 管道容量 |