【Linux 】文件描述符fd、重定向、缓冲区(超详解)

目录

[​编辑 系统接口进行文件访问](#编辑 系统接口进行文件访问)

[open 接口介绍](#open 接口介绍)

文件描述符fd

重定向

缓冲区

1、缓冲区是什么?

2、为什么要有缓冲区?

3、怎么办?


我们先来复习一下,c语言对文件的操作:

C默认会打开三个输入输出流,分别是stdin, stdout, stderr

复制代码
  1 #include<stdio.h>
  2 
  3 int main()
  4 {
  5     FILE *fp=fopen("log.txt","w");
  6     if(fp==NULL)
  7     {
  8         perror("error!");
  9         return 1;
 10     }
 11     fprintf(fp,"hello,%d,%s\n",10,"sxh");
 12     fclose(fp);
 13     return 0;
 14 }

系统接口进行文件访问

操作文件,除了上述C接口(当然,C++也有接口,其他语言也有),我们还可以采用系统接口来进行文件访问;

复制代码
  #include<stdio.h>
  #include<string.h>
   
  #include<sys/types.h>
  #include<sys/stat.h>
  #include<fcntl.h>
  #include<unistd.h>
   
  int main()
  {
      umask(0);
      int fd =open("log.txt",O_WRONLY | O_CREAT |O_TRUNC,0666);
      if(fd<0)
      {   
          perror("open");
          return 1;
      }
      
      //const char *message ="hello Linux!\n";
      const char * message ="aaaa\n";
      write(fd,message,strlen(message));
  
      close(fd);
  }

open("log.txt",O_WRONLY | O_CREAT |O_TRUNC,0666); :以写方式打开,不存在就创建,存在就先清空!相当于c语言中的 "w" 方式;

open 接口介绍

open man 2 open

#includ e <sys/types.h>

#include <sys/stat.h>

#include <fcntl.h>

int open(const char *pathname, int flags);

int open(const char *pathname, int flags, mode_t mode)

int creat(const char *pathname, mode_t mode);

pathname:要打开或创建的目标文件

flags: 打开文件时,可以传入多个参数选项,用下面的一个或者多个常量进行"或"运算,构成; 常见的参数有:

O_RDONLY: 只读打开

O_WRONLY: 只写打开

O_CREAT : 若文件不存在,则创建它。需要使用mode选项,来指明新文件的访问权限

O_APPEND: 追加写

mode: mode 只有 当 在 flags 中使用 O_CREAT 时才有效 , 否则被忽略.

返回值

成功:新打开的文件描述符

失败:-1

文件描述符fd

我们通过系统调用I/O打开一个文件的返回值,就是文件描述符:

int fd = open("log.txt",O_WRONLY | O_CREAT |O_TRUNC,0666);

这里fd 就是log.txt的文件描述符;

如果我们同时打开三个文件,并把这三个文件的文件描述符打印出来,会发现:

文件描述符是从3开始的,那0、1、2呢?

Linux进程默认情况下会有3个缺省打开的文件描述符:分别是标准输入0, 标准输出1, 标准错误2.

0,1,2对应的物理设备一般是:键盘,显示器,显示器

根据上述的图,我们可以知道:

open干什么?

1、创建file

2、开辟文件缓冲区的空间,加载文件数据(延后)

3、查看进程的文件描述符表

4、file地址,填入对应的表下标中

5、返回下标

重定向

看一下下面的代码:

复制代码
1 #include<stdio.h>
  2 #include<sys/types.h>
  3 #include<sys/stat.h>
  4 #include<fcntl.h>
  5 #include<unistd.h>
  6 #include<string.h>
  7 #include<stdlib.h>
  8 const char *filename="log.txt";
  9 
 10 int main()
 11 {
 12     //close(0);
 13     close(1);
 14     //close(2);
 15     int fd =open(filename,O_CREAT | O_WRONLY | O_TRUNC,0666);
 16     if(fd<0)
 17     {
 18         perror("open");
 19         return 1;
 20     }
 21     printf("printf,fd:%d\n",fd);
 22     fprintf(stdout,"fprintf,fd:%d\n",fd);
 23 
 24     fflush(stdout);
 25 
 26 
 27     close(fd);
 28     return 0;
 29 
 30 }

先看现象:

1、如果我们关闭的是0 :打印出来的log.txt的文件描述符是0 ;关闭的是2 ,则打印出来的文件描述符是2 ;关闭的是1 ,则不会显示出来;因为文件描述符1表示的是显示器,而我们把显示器关掉了自然打印不出来;

2、我们会在log.txt中打印出printf和fprintf的内容:

现象解释:

文件描述符规则:查看自己的文件描述表,分配最小的没有使用的文件描述符;

由于我们把显示器给关掉了,那么文件描述符1就是最小的没有使用的,这样log.txt就会被分配1为文件描述符;这其实就是一个重定向操作;

看下面的图:

一开始fd_array[1]指向的是显示器,由于close(1),加上open log.txt这样fd_array[1]指向的就是log.txt;

因为重定向的本质是在内核中改变文件描述符特点下标的内容,与上层无关;

fprintf()/printf() --->stdout --->struct FILE --->stdout ---->_fileno ==1;

所以fprintf()/printf() 看的就是_fileno ==1;由于重定向后log.txt的fd为1 ,自然fprintf()/printf()的内容打印到log.txt中;

如果我们一直用这种手动重定向的方式,比较麻烦;可以用系统调用:dup2()

看一下代码:

复制代码
  1 #include<stdio.h>
  2 #include<sys/types.h>
  3 #include<sys/stat.h>
  4 #include<fcntl.h>
  5 #include<unistd.h>
  6 #include<string.h>
  7 #include<stdlib.h>
  8 const char *filename="log.txt";
  9 
 10 int main()
 11 {
 12     int fd = open(filename,O_CREAT | O_WRONLY | O_TRUNC,0666);
 13     //dup2(fd,1);
 14 
 15     printf("hello world,fd:%d\n",fd);
 16     fprintf(stdout,"hello world\n");
 17     fflush(stdout);
 18     close(fd);
 19     return 0;
 20 }

上述的代码运行结果:会直接打印到显示器上;

如果把dup2(fd,1);复原:显示器上不会显示,而是在log.txt上显示

其实本质就是将fd覆盖1 指向下标的内容;

缓冲区

1、缓冲区是什么?

缓冲区就是一段内存空间

2、为什么要有缓冲区?

给上层提供高效的IO体验,间接提高整体效率

3、怎么办?

a、刷新策略

1、立即刷新 fflush(stdout)(c语言的刷新)、fsync(fd)(系统调用的刷新)

2、行刷新 (显示器)

3、全缓冲 (缓冲区写满,才刷新,普通文件)

b、特殊情况

进程退出,系统会自动刷新

强制刷新

相关推荐
程序员老舅12 分钟前
C++高并发精髓:无锁队列深度解析
linux·c++·内存管理·c/c++·原子操作·无锁队列
雨中风华25 分钟前
Linux, macOS系统实现远程目录访问(等同于windows平台xFsRedir软件的目录重定向)
linux·windows·macos
Yeats_Liao33 分钟前
评估体系构建:基于自动化指标与人工打分的双重验证
运维·人工智能·深度学习·算法·机器学习·自动化
爱吃生蚝的于勒1 小时前
【Linux】进程信号之捕捉(三)
linux·运维·服务器·c语言·数据结构·c++·学习
The森1 小时前
Linux IO 模型纵深解析 01:从 Unix 传统到 Linux 内核的 IO 第一性原理
linux·服务器·c语言·经验分享·笔记·unix
文艺理科生Owen1 小时前
Nginx 路径映射深度解析:从本地开发到生产交付的底层哲学
运维·nginx
期待のcode1 小时前
Redis的主从复制与集群
运维·服务器·redis
翼龙云_cloud1 小时前
腾讯云代理商: Linux 云服务器搭建 FTP 服务指南
linux·服务器·腾讯云
纤纡.1 小时前
Linux中SQL 从基础到进阶:五大分类详解与表结构操作(ALTER/DROP)全攻略
linux·数据库·sql
好好学习天天向上~~2 小时前
6_Linux学习总结_自动化构建
linux·学习·自动化