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

Linux 重定向和缓冲区

序言:

前面在Linux 基础文件IO操作-CSDN博客这篇博客里说了很多函数无论是在语言层还是在系统调用的方面。在调用系统调用open的时候会返回一个整型,在write传参的时候第一个参数是一个叫fd的东西,这个是什么东西?这篇博客会详细解释这个问题。

Ⅰ、文件描述符

什么是文件描述符?当调用open时成功就会返回一个整数这个就是文件描述符(file descriptor

一、C语言FILE和文件描述符的关系

在语言层我们并没有看见过文件描述符,我们在C语言中经常用的是文件指针,好像文件指针和文件描述符在一些功能上是相识的,他们之间有什么关系吗?

在C语言库中FILE是一个结构体,它的里边就包含了文件描述符,也就是说FILE是对fd的一层封装。下面我们来看一段代码来证明这一点:

在C语言层对系统调用做封装,用来使用更加方便和提升代码的可移植性。

下面我们再来看一段代码:

1 #include<stdio.h>2 #include<string.h>3 #include<sys/stat.h>4 #include<fcntl.h>5 #include<sys/types.h>                                                                                                                                                           6 7 8 int main()9 {10     int fd1 = open("log1.txt",O_WRONLY|O_CREAT|O_TRUNC);11     int fd2 = open("log2.txt",O_WRONLY|O_CREAT|O_TRUNC);12     int fd3 = open("log3.txt",O_WRONLY|O_CREAT|O_TRUNC);13     int fd4 = open("log4.txt",O_WRONLY|O_CREAT|O_TRUNC);14 15     printf("fd1 = %d\n",fd1);16     printf("fd2 = %d\n",fd2);17     printf("fd3 = %d\n",fd3);18     printf("fd4 = %d\n",fd4);19     return 0;20 }

在这里我们会很奇怪为什么我们打开的文件的文件描述符是从3开始而不是从0。当我们的代码开始运行的时候有三个文件流会默认打开,在C语言中叫stdin,stdout, stderr ,这三个文件流占据着0 ,1 ,2  下面我们来证明一下:

 1 #include<stdio.h>2 #include<string.h>3 #include<sys/stat.h>4 #include<fcntl.h>5 #include<sys/types.h>6 7 8 int main()9 {10     FILE* fd = fopen("log.txt","w");11 12     printf("stdin = %d\n", stdin->_fileno );                                                                                                                                    13     printf("stdout = %d\n", stdout->_fileno );14     printf("stderr = %d\n", stderr->_fileno );15     printf("log.txt = %d\n", fd->_fileno );16 17 18     fclose(fd);19     return 0;20 }

二、为什么要有文件操作符?

上一个博客我们说到我们要对文件进行管理采用 “先组织,再管理” 的思想所以有了struct_file组织各种文件的各种信息,如何去管理这些结构体呢?

再task_struct中会有一个指针指向指针数组,这些指针数组中放着各个struct_file的指针,这个指针数组就叫做文件描述表,数组的下标就是文件描述符,所以文件描述符就是数组的下标,操作系统通过这些文件描述符就可以去管理文件。

三、文件描述符的分配规则

当一个文件打开的时候就会把它的struct_file指针按照最小且没有被使用的地址存放,这块地址的下标作为这个文件的fd返回给用户。

1 #include<stdio.h>2 #include<string.h>3 #include<sys/stat.h>4 #include<fcntl.h>5 #include<sys/types.h>6 7 8 int main()9 {10     fclose(stdin);11     FILE* fd = fopen("log.txt","w");12     printf("log.txt = %d\n", fd->_fileno );                                                                                                                                     13     printf("stdout = %d\n", stdout->_fileno );14     printf("stderr = %d\n", stderr->_fileno );15 16 17     fclose(fd);18     return 0;19 }

Ⅱ、重定向操作

一、重定向的本质

在linux中可以通过一些指令“ > ,>>  , <”实现重定向操作。我们如何去实现重定向换句话来说重定向的本质是什么?我们在上面看见C语言中的stdin,stdout,stderr 的文件操作符分别是0,1,2,如果我们打开一个新的文件那么它的文件描述符就是 3 ,如果我们能将files_struct array[3]里的地址复制一份给files_struct array[1]里,那么也就相当于文件描述符为1指向的是我们打开的是我们打开的文件,怎么去改变这两个值呢?我们可以用系统调用dup2。

参数中的oldfd是要复制的地址的fd,而newfd是被复制地址的fd。按照我们上面说的例子那么oldfd是 3 我们打开的文件,而newfd是 fd = 1的这个文件。知道这个系统调用了以后我们可以做一个实验。

下面看一段代码:

 1 #include<stdio.h>2 #include<string.h>3 #include<sys/stat.h>4 #include<fcntl.h>5 #include<sys/types.h>6 #include<unistd.h>7 8 int main()9 {10     int fd = open("log.txt",O_WRONLY|O_CREAT|O_TRUNC);11     dup2(fd,1);12     close(fd);13     printf("hello dup2\n");                                                                                                                                                     14     return 0;15 }

为什么我们printf没有向显示器上打而是向我们的文件里打呢?我们知道stdin,stdout,stderr分别是键盘文件,显示器文件,显示器文件,他们是固定的fd,在C语言在分装的函数比如printf,scanf在函数里封装了fd,所以他们的fd是固定的,那么我们通过更改fd = 1里的指针我们就可以实现输出重定向和追加重定向,更改fd = 0里的指针可以实现输入重定向。综上所述重定向的本质就是对文件描述符表对下标 0,1的改变。

=========================================================================

本篇关于Linux的文件理解与操作的介绍就暂告段落啦,希望能对大家的学习产生帮助,欢迎各位佬前来支持纠正!!!

http://www.lryc.cn/news/596772.html

相关文章:

  • docker-desktop启动失败
  • leetcode 1695. 删除子数组的最大得分 中等
  • importlib.import_module() 的用法与实战案例
  • MySQL 学习一 存储结构和log
  • HTML结构解析
  • SpringAOP的实现原理和场景
  • SQLAlchemy 2.0简单使用
  • c++day05(ASCII)
  • 性能测试-从0到1搭建性能测试环境Jmeter+Grafana+influxDB+Prometheus+Linux
  • “鱼书”深度学习入门 笔记(1)前四章内容
  • torchvision.transforms 与 MONAI 数据增强的异同
  • C# 类 封装 属性 练习题
  • RabbitMQ-交换机(Exchange)
  • Ajax第一天
  • 美团视觉算法面试30问全景精解
  • freertos关键函数理解 uxListRemove
  • JavaScript 01 JavaScript 是什么
  • 在 Linux 上安装 `pgvector`(这是一个 PostgreSQL 的向量类型扩展,常用于处理嵌入向量,便于进行向量相似度搜索)
  • JavaScript 03 严格检查模式Strict字符串类型详解
  • 从零开始学习大模型之文本数据处理
  • Kotlin伴生对象
  • Python的界面美化库 QDarkStyleSheet
  • 循环神经网络--NLP基础
  • 2025年6月GESP(C++五级):最大公因数
  • 【第三节】Class与Style绑定
  • p5.js 圆弧的用法
  • Git GitHub精通:前端协作开发的“瑞士军刀“!
  • ubuntu22.04 录视屏软件推荐
  • Vercel AI SDK 3.0 学习入门指南
  • Android-API调用学习总结