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

Linux重定向与缓冲区

目录

文件描述符的分配规则

重定向

使用 dup2 系统调用

FILE


文件描述符的分配规则

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>int main()
{int fd = open("myfile", O_RDONLY);if(fd < 0){perror("open");return 1;}printf("fd: %d\n", fd);close(fd);return 0;
}

输出发现是 fd: 3

关闭0或者2,再看

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>int main()
{close(0);//close(2);int fd = open("myfile", O_RDONLY);if(fd < 0){perror("open");return 1;}printf("fd: %d\n", fd);close(fd);return 0;
}

发现是结果是: fd: 0 或者 fd 2 可见,文件描述符的分配规则:在files_struct数组当中,找到当前没有被使用的最小的一个下标,作为新的文件描述符。

重定向

那如果关闭1呢?看代码:

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>int main()
{close(1);int fd = open("myfile", O_WRONLY|O_CREAT, 00644);if(fd < 0){perror("open");return 1;}printf("fd: %d\n", fd);fflush(stdout);close(fd);exit(0);
}

此时,我们发现,本来应该输出到显示器上的内容,输出到了文件 myfile 当中,其中,fd=1。这种现象叫做输出重定向。常见的重定向有:>, >>,<。

那重定向的本质是什么呢?

实际上我们的上层是不会变的,也就是说操作系统还是只看fd,但是呢fd对应的文件结构体内容变了,指向了其它文件的地址就会发生这种效果。

使用 dup2 系统调用

函数原型如下:

#include <unistd.h>int dup2(int oldfd, int newfd);
//int fd = open(filename,O_CREAT | O_WRONLY | O_TRUNC,0666);int fd = open(filename,O_CREAT | O_WRONLY | O_APPEND,0666);dup2(fd,1);printf("hello world\n");fprintf(stdout, "hello world\n");

printf是C库函数当中的IO函数,一般往 stdout 中输出,但是stdout底层访问文件的时候,找的还是fd:1, 但此时,fd:1 下标所表示内容,已经变成了log.txt的地址,不再是显示器文件的地址,所以,输出的任何消息都会往文件中写入,进而完成输出重定向。

FILE

  • 因为IO相关函数与系统调用接口对应,并且库函数封装系统调用,所以本质上,访问文件都是通过fd访问的。
  • 所以C库当中的FILE结构体内部,必定封装了fd。

来段代码在研究一下:

#include <stdio.h>
#include <string.h>int main()
{const char *msg0="hello printf\n";const char *msg1="hello fwrite\n";const char *msg2="hello write\n";printf("%s", msg0);fwrite(msg1, strlen(msg0), 1, stdout);write(1, msg2, strlen(msg2));fork();return 0;
}

运行出结果:

hello printf
hello fwrite
hello write

但如果对进程实现输出重定向呢? ./hello > file , 我们发现结果变成了:

hello write
hello printf
hello fwrite
hello printf
hello fwrite

我们发现 printf fwrite (库函数)都输出了2次,而 write 只输出了一次(系统调用)。为什么呢?肯定和 fork有关!

  • 一般C库函数写入文件时是全缓冲的,而写入显示器是行缓冲。
  • printf fwrite 库函数会自带缓冲区(进度条例子就可以说明),当发生重定向到普通文件时,数据的缓冲方式由行缓冲变成了全缓冲。
  • 而我们放在缓冲区中的数据,就不会被立即刷新,甚至fork之后
  • 但是进程退出之后,会统一刷新,写入文件当中。
  • 但是fork的时候,父子数据会发生写时拷贝,所以当你父进程准备刷新的时候,子进程也就有了同样的 一份数据,随即产生两份数据。
  • write 没有变化,说明没有所谓的缓冲。、

综上: printf fwrite 库函数会自带缓冲区,而 write 系统调用没有带缓冲区。另外,我们这里所说的缓冲区, 都是用户级缓冲区。其实为了提升整机性能,OS也会提供相关内核级缓冲区,不过不在我们讨论范围之内。 那这个缓冲区谁提供呢? printf fwrite 是库函数, write 是系统调用,库函数在系统调用的“上层”, 是对系统 调用的“封装”,但是 write 没有缓冲区,而 printf fwrite 有,足以说明,该缓冲区是二次加上的,又因为是 C,所以由C标准库提供。

http://www.xdnf.cn/news/6201.html

相关文章:

  • AI时代的弯道超车之第七章:如何用AI赋能创业?
  • 缺乏自动化测试,如何提高测试效率
  • 酒店旅游类数据采集API接口之携程数据获取地方美食品列表 获取地方美餐馆列表 景点评论
  • CodeBuddy Craft,我的编程搭子
  • element基于表头返回 merge: true 配置列合并
  • Oracle版本、补丁及升级(12)——补丁及补丁集
  • REVERSE学习笔记(攻防世界xxxorrr)
  • 【Java学习笔记】==运算符
  • 解决常见数据库问题:保障数据安全与稳定的全方位指南
  • 模板源码建站、定制建站和SaaS 建站有什么区别?企业建站应该怎么选?
  • C++引用编程练习
  • XILINX-DDR4-自定义componet(x8)-之一
  • 六西格玛觉醒:一场数据思维的启蒙运动​
  • 【江苏省】《信息技术应用创新软件适配改造成本评估规范》(DB32/T 4935-2024)-标准解读系列
  • 【Linux Nano Vim快捷键大全】
  • 基于EFISH-SCB-RK3576/SAIL-RK3576的康复训练机器人技术方案‌
  • Linux下批量提取子文件夹文件到当前目录
  • libmemcached库api接口讲解二
  • 股指期货套期保值怎么操作?
  • 【Linux】shell内置命令fg,bg和jobs
  • tensorflow安装及简单例程学习
  • 字符田字格绘制
  • Java的多线程笔记
  • 企业报表平台如何实现降本增效
  • requestAnimationFrame 与 requestIdleCallback 对比
  • JavaScript中执行上下文和执行栈是什么?
  • Linux `whoami` 命令深度解析与高阶应用指南
  • 【USRP】在linux下安装python API调用
  • 保姆级!MeloTTS部署 且支持流式接口
  • Vue3在使用渲染函数h时候使用v-loading