当前位置: 首页 > article >正文

【Linux基础IO】文件描述符分配规则 重定向

目录

前言

1. 文件fd分配规则

2. 重定向 

2.1 输入重定向&输出重定向

2.2  Linux指令中的重定向

 2.3 重定向中的标准输出与标准错误

总结


前言

        接上文,了解完了文件,本文就来聊一聊文件描述符的分配规则,以及使用方法(重定向);

在这里插入图片描述

1. 文件fd分配规则

        文件标识符为0、1、2的文件默认打开,read读取 stdin 文件的数据(读到buffer里),write 向 stdout中写数据;

  • 标准输入:stdin(键盘)        0
  • 标准输出:stdout(显示器)  1
  • 标准错误:stderr(显示器)   2

 比如下面的代码:

char buffer[1024];
ssize_t s = read(0,buffer,1024);//打开了标准输入
if(s > 0)
{
    buffer[s] = 0;
    write(1,buffer,strlen(buffer))
    // printf("echo# %s\n",buffer);
}

使用示例中,没有打开0、1标识符的文件,却可以直接使用 由此也证明:0、1、2被默认打开;

 如果关闭0或者2号文件,那么打开指定文件时,文件的fd就是0或者2; 验证代码如下:

close(2)
int fd = open(FILE_NAME,O_CREAT | O_WRONLY | O_TRUNC,0666);
if(fd < 0)
{
    perror("open");
    return 1;
}
printf("fd:%d\n" fd);

close(fd);

由此我们可以推断出fd的分配规则:

  • 进程启动时默认打开0、1、2,可以直接使用0、1、2进行数据访问
  • 从上到下进行扫描,没有被使用的数据位置,分配给指定的打开文件 

2. 重定向 

        重定向的本质,其实就是修改特定文件fd的下标内容;也就是说上层的fd不变,底层fd指向内容在改变;

2.1 输入重定向&输出重定向

close(1);
int fd = open(FILE_NAME,O_CREAT | O_WRONLY | O_TRUNC,0666).
if(fd < 0)
{
    perror("open");
    return 1;
}
printf("fd:%d\n" fd);
printf("stdout->fd:%d\n",stdout->_fileno);
fflush(stdout);
close(fd);

上述的例子中,原本要在显示器上输出的内容,输出到了log.txt文件中; 

        fflush的作用:刷新缓冲区;之前提到在C语言库里边会提供一个缓冲区,如果没有fflush刷新缓冲区,数据就没办法从缓冲区写到文件当中,后续会进行详细解释;

程序逻辑图:

示例中,修改了 1 位置的文件,把原本的stdout换成了log.txt;而 printf 中的 stdout (结构体)中有一个fileno=1 ;  操作系统只认文件描述符(fileno),fileno位置的文件是谁就打开谁;  所以原本在显示器上输出的内容就修改成了打开 log.txt 进行写入 这个过程也就是重定向;

 是否存在更直接的方法来达到重定向或者说,有没有一个接口进行文件描述符级别的拷贝?

 如下图:

 有的他就是dup接口,dup2可以做到数组内容的拷贝

dup接口是拷贝原有的文件描述对象地址到新的位置并返回下标(文件描述符),内部可以理解为采用了引用计数;

dup2将指定文件描述符对应的内容拷贝到指定位置;

注意:文件描述符表中放的文件描述对象的地址;

拷贝过去后,两个位置的文件描述对象地址都是 log.txt,调用时如果其中个对文件进行了关闭,这种情况怎么解决? 

Linux中的解决方法是引用计数,统计有几个指针指向了文件描述对象 : atomic_long_t、f_count;

 将屏幕中输出的内容输出到文件中示例代码:

int main()
{
    int fd = open(FILE_NAME,O_WRONLY | O_CREAT | O_TRUNC,0666);
    if(fd < 0)
    {
        perror("open");
        return 1;
    }
    dup2(fd,1);
    //close(fd) // 关闭不需要的文件描述符

    printf("hello printf!\n");
    fprintf(stdout,"hello fprintf!\n")
    return 0;
}

 这里需要注意的点:文件描述符的重定向仅对当前进程有效,下次启动操作系统会自动将标准输出(即文件描述符 1)恢复为默认的终端输出;

提示:fprintf 接口的作用是将格式化数据输出到指定的 文件流;

建议:

        在这个代码中,将文件描述符 fd 重定向到标准输出 1 后,1fd 都指向了同一个文件,所以选择关闭其中任何一个文件描述符都可以,因为它们共享同一个文件对象;在这种情况下,建议关闭 fd,因为 1 是标准输出的文件描述符,一般情况下不推荐关闭它,特别是在程序后续可能需要标准输出的情况下;

输入重定向也是类似,可以类比一下:

int fd = open(FILE_NAME,O_RDONLY);
if(fd < 0)
{
    perror("open");
    return 1;
}

dup2(fd,0);//输入重定向

char buffer[1024];

fread(buffer,1,1024,stdin);

printf("%s\n",buffer);

close(fd);

2.2  Linux指令中的重定向

Linux中的重定向怎么用的?

重定向功能其实就是我们以前用的<(输入重定向)、>(输出重定向)、>>(追加重定向);

 它们和我们现在了解的不一样啊,它是怎么实现的?

        把ls-al输出的内容重定向到log.txt中,这些其实都是bash帮我做的,把“s-al>log.txt”这个字符串进行分割判断,后半部分log.txt 是文件名,中间的符号>是重定向的操作方式,ls -a是重定向的内容;有了这些我们就可以通过程序来实现重定向;

 2.3 重定向中的标准输出与标准错误

 看下面这个代码:

int main()
{
    fprintf(stdout, "hello stdout\n");
    fprintf(stderr, "hello stderr\n");
    return 0;
}

 执行结果:

 

myfile执行结果一条数据输出到了 log.txt 中,一条数据并没有输出到log.txt中,而是输出到了显示器中;这是为什么?

        >为输出重定向,bash会修改1号位置的文件描述对象地址,而2号位置的stderr也是显示器,并不受影响,输出重定向并不影响标准错误

如果想要同时将stdout和stderr都重定向输出到log.txt文件中怎么操作?

 解释:

  • 前半部分:将myfile执行结果输出重定向到log.txt,
  • 后半部分:标准错误的输出重定向,怎么重定向?  将1(标准输出)位置文件描述对象地址,放到2号位置一份;

通过上述的示例我们可以发现 stdout 和 stderr 它们完全不一样,虽然都可以显示到显示器上;
C语言中的 printf 和 perror;C++中的 cout 和 cerr 一个是写入到标准输出,一个是写到标准错误;

 使用技巧:

我们可以通过指令间两个输出进行分离,分别写入到不同的文件中:


以上便是本文的全部内容,希望对你有所帮助,最后感谢阅读!


http://www.kler.cn/a/384944.html

相关文章:

  • 云端到本地:深度学习日志与模型文件一键传输【详解 SCP 命令】
  • 基于 Transformer 的语言模型
  • LabVIEW编程过程中为什么会出现bug?
  • Java多线程详解⑤(全程干货!!!)线程安全问题 || 锁 || synchronized
  • Java | Leetcode Java题解之第546题移除盒子
  • 将vscode的终端改为cygwin terminal
  • 从0开始学习Linux——文件目录
  • docker安装zookeeper,以及zk可视化界面介绍
  • Me-LLaMA——用于医疗领域的新型开源大规模语言模型
  • 如何在 Vue.js 中优化 Element UI 长文本显示
  • 【9695】基于springboot+vue的学生就业管理系统
  • Instagram 青少年账户:安全新升级
  • 反转链表(Leetcode)
  • 与同行争夺白牌商品市场 京东补贴100亿扶持1万家产业带工厂
  • commonJS | module.exports vs exports
  • 推荐FileLink数据跨网摆渡系统 — 安全、高效的数据传输解决方案
  • 说说webpack proxy工作原理?为什么能解决跨域
  • Docker篇(registry私服)
  • 电路设计中的防接反电路
  • 《我的百科全书》——持续更新
  • 细说STM32单片机USART中断收发RTC实时时间并改善其鲁棒性的方法
  • 《ElementPlus 与 ElementUI 差异集合》Icon 图标 More 差异说明
  • git中的gitignore文件
  • PHP+MySQL开发的一套招聘管理系统开发案例源码功能介绍
  • Dockerfile的使用
  • 深入理解RocketMQ延迟消息机制原理