0,1,2对应STDIN_FILENO,STDOUT_FILENO,STDERR_FILENO三个标准输入,输出,出错
#include <fcntl.h>
int open(const char* path, int oflag, ...)'
path就是文件名字
oflag参数
首先必须5项选1:O_RDONLY只读 O_RDONLY只写 O_RDWR读写 O_EXEX只执行 O_SEARCH只搜索
下面是可选的:选几个常用的
O_APPEND 每次写时追加到文件尾
O_CREATE 文件不存在的时候创建它
O_SYNC 每次write等待物理I/O操作完成
O_TRUNC 如果文件存在 而且是只写或者读写打开,会清空文件内容
其实等于
open(path, O_WRONLY|O_CREAT|O_TRUNC,mode);
只是将打开文件的计数减1,计数为0才会关闭文件。进程终止就会关闭所以其打开的文件。
off_t lseek(int fd, off_t offset, int whence);
off_t currpos;
currpos = lseek(fd, 0, SEEK_CUR);
如果这个返回-1,代表文件描述符指向一个管道,FIFO,socket等。最好用-1来判断,不要用小于0来判断,因为有的设备返回会有负数。
多步组成的一个操作,不会被其他进程打断。
pread,pwrite函数,就是将lseek和write,read组成一个操作。成为原子操作,分开可能会被其他进程打断。
这两个函数都是对fd重定向,在另一篇转载的博客有比较详细的说明
dup函数 等效 fcntl_fd, F_DUPFD, 0);
dup2(fd, fd2)等效
close(fd2);
fcntl_fd, F_DUPFD, fd2);
但是dup2是原子操作
下面举个adbd中的dup2函数例子
static int create_subproc_raw(const char *cmd, const char *arg0, const char *arg1, pid_t *pid) { // 0 is parent socket, 1 is child socket int sv[2]; if (adb_socketpair(sv) < 0) { printf("[ cannot create socket pair - %s ]\n", strerror(errno)); return -1; } *pid = fork(); if (*pid < 0) { printf("- fork failed: %s -\n", strerror(errno)); adb_close(sv[0]); adb_close(sv[1]); return -1; } if (*pid == 0) { adb_close(sv[0]);//子进程关闭0端 init_subproc_child(); dup2(sv[1], STDIN_FILENO); dup2(sv[1], STDOUT_FILENO); dup2(sv[1], STDERR_FILENO); adb_close(sv[1]);//关闭原来的sockpair的1端,无用了。因为有3个标准的fd指向了它 execl(cmd, cmd, arg0, arg1, NULL); fprintf(stderr, "- exec '%s' failed: %s (%d) -\n", cmd, strerror(errno), errno); exit(-1); } else { adb_close(sv[1]);//父进程关闭1端 return sv[0]; } }这里主进程创建了一对socketpair,然后fork一个子进程。子进程复制了父进程的文件描述符表。因此这对sockpair被打开了两次。主进程返回了0端,1端
0-> shell 1-> shell 2-> shell dup2之后
0-> sockpair 1端 1-> sockpair 1端 2-> sockpair 1端
而原来sockpair1端的fd其实没用了,就可以关闭了。
int fcntl(int fd , int cmd, ...);
设置fd的属性
常用cmd
F_SETFL 设置文件的状态标志比如 O_SYNC
F_GETFL 获取文件的状态标志
F_DUPFD fd重定向
F_SETFD 设置fd标志,比如FD_CLOEXEC代表不能使用excel开启这个fd