unix编程(一)文件I/O

文件描述符

0,1,2对应STDIN_FILENO,STDOUT_FILENO,STDERR_FILENO三个标准输入,输出,出错


open函数

#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 如果文件存在 而且是只写或者读写打开,会清空文件内容


create函数

其实等于

open(path, O_WRONLY|O_CREAT|O_TRUNC,mode);


close函数

只是将打开文件的计数减1,计数为0才会关闭文件。进程终止就会关闭所以其打开的文件。


lseek函数

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组成一个操作。成为原子操作,分开可能会被其他进程打断。


dup dup2函数

这两个函数都是对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其实没用了,就可以关闭了。


函数fcntl

int fcntl(int fd , int cmd, ...);

设置fd的属性

常用cmd

F_SETFL 设置文件的状态标志比如 O_SYNC

F_GETFL 获取文件的状态标志

F_DUPFD fd重定向

F_SETFD 设置fd标志,比如FD_CLOEXEC代表不能使用excel开启这个fd




你可能感兴趣的:(unix编程(一)文件I/O)