5.dup和dup2和fcntrl及标准IO


5.1.dup实现文件共享及文件重定位
(1)dup函数对fd进行复制,会返回1个新的文件描述符(譬如原来的fd是3,则返回的fd就是4);dup函数不能指定复制后得到的fd的数值,而是由操作系统内部自动分配的,分配的原则遵守fd分配的原则;dup2函数修复了该缺陷,则平时项目中实际使用时应根据具体情况来决定用dup还是dup2。
(2)dup返回的fd和原来的oldfd都指向oldfd打开的那个动态文件,操作这两个fd实际操作的都是oldfd打开的那个文件,即构成了文件共享(fd和oldfd均指向同一个文件表,即两个文件指针相同);dup返回的fd和原来的oldfd同时向1个文件读/写时,结果是接续读/写。
(3)我们知道0、1、2这三个fd被标准输入、输出、错误通道占用,而且我们可以关闭这三个fd,则我们可使用close和dup配合进行文件的重定位;首先通过close(1)关闭标准输出(关闭后printf输出到标准输出的内容就看不到了),然后使用dup重新复制得到1这个fd(即把oldfd对应的文件和1这个标准输出通道给绑定起来了),即实现了标准输出的重定位。


5.2.dup2实现文件共享及重定位命令>
(1)dup2和dup的作用相同,都是复制1个新的文件描述符,但dup2允许用户指定新的文件描述符的数字,使用方法看man手册函数原型即可;dup2和dup实现的共享文件的所有特性都相同。
(2)linux中的shell命令执行后,打印结果都是默认进入stdout的(本质上是因为这些命令譬如ls、pwd等都是调用printf进行打印的),则我们可以在linux的终端shell中直接看到命令执行的结果;能否想办法把ls、pwd等命令的输出给重定位到11个文件中(譬如test.txt)去,实际上linux终端支持1个重定位的符号>可实现此功能(譬如ls > test.txt)。
(3)>的实现原理即利用open+close+dup,open打开1个文件test.txt,然后close关闭stdout,然后dup将1和test.txt文件关联起来即可。


5.3.fcntl的原型和作用
(1)fcntl函数是1个多功能文件管理的工具箱,接收2个参数+1个变参;第1个参数是fd表示要操作哪个文件,第2个参数是cmd表示要进行哪个命令操作,变参是用来传递参数的,要配合cmd来使用。
(2)cmd的格式类似于F_XXX,不同的cmd具有不同的功能,学习时没必要去把所有的cmd的含义都弄清楚,只需要弄明白1个作为案例,搞清楚它怎么看怎么用就行了,其它的是类似的,其它的当我们在使用中碰到了1个fcntl的不认识的cmd时再去查man手册即可。
(3)F_DUPFD该cmd的作用是复制文件描述符(类似dup和dup2);该命令的功能是从可用的fd数字列表中找1个>=arg的数字作为oldfd的1个复制的fd;dup2返回的是我们指定的那个newfd否则就会出错,但F_DUPFD命令返回的是>=arg的最小的那1个数字。


5.4.标准IO和文件IO
(1)标准IO是C库函数,而文件IO是linux系统的API;C语言库函数是由系统API封装而来的,但库函数因为多了1层封装,则比系统API要更加好用一些;系统API在不同的操作系统之间是不能通用的,但C库函数在不同操作系统中几乎是一样的,则C库函数具有可移植性而API不具有可移植性;性能上和易用性上看,C库函数一般要好一些,譬如IO,文件IO是不带缓存的,而标准IO是带缓存的,因此标准IO比文件IO性能要更高。
(2)常见的标准IO库函数有fopen、fclose、fwrite、fread、ffulsh(清缓存)、fseek。


5.dup_share_relocate
/*
 * 公司:XXXX
 * 作者:Rston
 * 博客:http://blog.csdn.net/rston
 * GitHub:https://github.com/rston
 * 项目:dup和dup2和fcntrl及标准IO
 * 功能:使用dup实现文件共享和文件重定位。
 */
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>

#define PATHNAME "./test.txt"

int main(int argc, char **argv)
{
    int fd1 = -1, fd2 = -1;
    int ret = -1;

    // 若文件存在则截断,若不存在则创建
    fd1 = open(PATHNAME, O_RDWR | O_CREAT | O_TRUNC, 0644);
    if (fd1 < 0)
    {
        perror("open error");
        exit(-1);
    }
    printf("fd1 = %d.\n", fd1);

    close(1);                   // 关闭标准输出1
    fd2 = dup(fd1);             // fd1和标准输出1共享同一个文件PATHNAME
    printf("fd2 = %d.\n", fd2); // 在PATHNAME文件中查看该输出信息

    // dup返回的fd和原来的oldfd同时向1个文件读/写时,结果是接续读/写
    while (1)
    {
        ret = write(fd1, "ab.\n", 4);
        if (ret < 0)
        {
            perror("write error");
            exit(-1);
        }

        sleep(1);

        printf("cd.\n");
    }

    close(fd1);
    close(fd2);
    exit(0);
}

5.dup2_share
/*
 * 公司:XXXX
 * 作者:Rston
 * 博客:http://blog.csdn.net/rston
 * GitHub:https://github.com/rston
 * 项目:dup和dup2和fcntrl及标准IO
 * 功能:使用dup2实现文件共享。
 */
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>

#define PATHNAME "./test.txt"

int main(int argc, char **argv)
{
    int fd1 = -1, fd2 = -1;
    int ret = -1;

    // 若文件存在则截断,若不存在则创建
    fd1 = open(PATHNAME, O_RDWR | O_CREAT | O_TRUNC, 0644);
    if (fd1 < 0)
    {
        perror("open error");
        exit(-1);
    }
    printf("fd1 = %d.\n", fd1);

    fd2 = dup2(fd1, 20);        // fd2和fd1指向同一个文件,对应同一个文件指针
    printf("fd2 = %d.\n", fd2);

    // dup2返回的fd和原来的oldfd同时向1个文件读/写时,结果是接续读/写
    while (1)
    {
        ret = write(fd1, "ab", 2);
        if (ret < 0)
        {
            perror("write error");
            exit(-1);
        }

        sleep(1);

        ret = write(fd2, "cd", 2);
        if (ret < 0)
        {
            perror("write error");
            exit(-1);
        }
    }

    close(fd1);
    close(fd2);
    exit(0);
}

5.fcntl_dup2_share
/*
 * 公司:XXXX
 * 作者:Rston
 * 博客:http://blog.csdn.net/rston
 * GitHub:https://github.com/rston
 * 项目:dup和dup2和fcntrl及标准IO
 * 功能:使用fcntl模拟dup2。
 */
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>

#define PATHNAME "./test.txt"

int main(int argc, char **argv)
{
    int fd1 = -1, fd2 = -1;
    int ret = -1;

    // 若文件存在则截断,若不存在则创建
    fd1 = open(PATHNAME, O_RDWR | O_CREAT | O_TRUNC, 0644);
    if (fd1 < 0)
    {
        perror("open error");
        exit(-1);
    }
    printf("fd1 = %d.\n", fd1);

    fd2 = fcntl(fd1,  F_DUPFD, 20);     // fd2和fd1指向同一个文件,对应同一个文件指针
    printf("fd2 = %d.\n", fd2);

    // fcntl返回的fd和原来的oldfd同时向1个文件读/写时,结果是接续读/写
    while (1)
    {
        ret = write(fd1, "ab", 2);
        if (ret < 0)
        {
            perror("write error");
            exit(-1);
        }

        sleep(1);

        ret = write(fd2, "cd", 2);
        if (ret < 0)
        {
            perror("write error");
            exit(-1);
        }
    }

    close(fd1);
    close(fd2);
    exit(0);
}

5.file_io_example
/*
 * 公司:XXXX
 * 作者:Rston
 * 博客:http://blog.csdn.net/rston
 * GitHub:https://github.com/rston
 * 项目:dup和dup2和fcntrl及标准IO
 * 功能:实现1个简单的文件IO读写操作。
 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define PATHNAME "./test.txt"

int main(int argc, char **argv)
{
    FILE *fp = NULL;
    size_t len = -1;
    char str[] = "Linux Is Great";
    char readbuf[100] = {0};

#if 0
    // 以可读写方式打开该文件,若文件存在则截断,若文件不存在则创建
    fp = fopen(PATHNAME, "w+");
    if (NULL == fp)
    {
        perror("fopen error");
        exit(-1);
    }

    len = fwrite(str, sizeof(str[0]), sizeof(str)/sizeof(str[0]), fp);
    printf("len of fwrite is %d.\n", len);
    printf("the content of fwrite is [%s].\n", str);
#endif  

#if 1   
    // 以可读写方式打开该文件
    fp = fopen(PATHNAME, "r+");
    if (NULL == fp)
    {
        perror("fopen error");
        exit(-1);
    }

    memset(readbuf, 0, sizeof(readbuf));
    len = fread(readbuf, sizeof(char), sizeof(readbuf), fp);
    printf("len of fread is %d.\n", len);
    printf("the content of fread is [%s].\n", readbuf);
#endif

    fclose(fp);
    exit(0);
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值