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

2024-10-13-B fd 重定向 缓冲区

1   一切皆文件

1.1   虚拟文件系统

在系统层面,做了一层软件的封装,struct file 里有操作表(即函数指针的集合),可以调用底层的读写方法。虚拟文件系统(VFS)是一种神奇的抽象,它使得 “一切皆文件” 哲学在 Linux 中成为了可能。 (类比C++多态)

1.2   为何C/C++喜欢做封装

(1) 方便用户操作 

以“文本写入 vs 二进制写入”举例,在操作系统层面全是二进制,语言层面进行转化变为文本

(2) 提高语言的可移植性

如果不是Linux而是其他操作系统呢?C库函数 ---> 系统调用;FILE ---> fd(源代码编译成不同版本的库)

封装可以“屏蔽差异”

1.3   文件内核缓冲区

写入:

打开一个 myfile 文件,创建对应的 struct file,里面包含操作表和文件内核缓冲区address_space,write() (拷贝函数,把数据从用户拷贝至内核)把要写入的内容拷贝至文件的内核缓冲区,如果需要的话,可通过file->ops->write()将数据刷新到文件中(由OS自主决定)。

空文件写入,拷贝刷新即可;修改的本质,是先读取再写入。

为何有缓冲区?因为外设比较慢,缓冲区的存在可以变相提高IO效率。

一个进程,能在PCB中找到file对象,通过file对象,既能找到文件的操作表,又能找到文件对应的属性集,还能找到文件对应的文件内核缓冲区。

1.4   重定向

    close(0);
	int fd1 = open("return_test1.txt", O_WRONLY | O_CREAT | O_APPEND, 0666);
	int fd2 = open("return_test2.txt", O_WRONLY | O_CREAT | O_APPEND, 0666);
	int fd3 = open("return_test3.txt", O_WRONLY | O_CREAT | O_APPEND, 0666);
	int fd4 = open("return_test4.txt", O_WRONLY | O_CREAT | O_APPEND, 0666);

./ofi
fd1 of open(): 0
fd2 of open(): 3
fd3 of open(): 4
fd4 of open(): 5

进程打开文件,需要给文件分配新的fd时,fd的分配规则是以最小的且没有被使用的为优先

 重定向:把 fd_array 中特定下标对应的元素替换后,如close(1),上层不知道(printf->stdout->fileno=1),本来往显示器文件写入的变为了往新的文件写入。

系统调用:int dup2(int oldfd, int newfd)
dup2() makes newfd be the copy of oldfd, closing newfd if necessary

如果要做输出重定向,可以把文件的地址(fd)覆盖到 fd_array[1] 中,即 dup2(fd, 1)
(联想记忆:fd活得久,就old)

int fd = open("log.txt", O_CREAT | O_WRONLY | O_TRUNC, 0666);
printf("HELLO FD: %d\n", fd);
fprintf(stdout, "HELLO FD: %d\n", fd);
fputs("HELLO LINUX\n", stdout);
const char *msg = "hello fwrite\n";
fwrite(msg, 1, strlen(msg), stdout);

往显示器里写入

HELLO FD: 3
HELLO FD: 3
HELLO LINUX
hello fwrite

使用 dup2(fd, 1);

$ cat log.txt 
HELLO FD: 3
HELLO FD: 3
HELLO LINUX
hello fwrite

1.4.1    命令行中重定向内容的解析

"ls -a -l -n" < hello.txt

"ls -a -l -n" > hello.txt

"ls -a -l -n" >> hello.txt

//全局变量(重定向相关)
#define NoRedir 0
#define InRedir 1
#define OutRedir 2
#define AppRedir 3

int redirtype = NoRedir;
char *filename = nullptr;
//过滤空格
#define TrimSpace(pos) do{\ //while(0)的作用是形成代码块,可以整体替换
        while(isspace(*pos)){\
                pos++;\
        }\
}while(0)
bool ParseCommandLine(char commandline_buffer[], int len){
//......

        //重定向
        redir = NoRedir;
        filename = nullptr;

        //"ls -a -l -n" > file.txt
        int end = len - 1;
        while(end >= 0){
                if(commandline_buffer[end] == '<'){
                        redir = InRedir;
                        filename = &commandline_buffer[end] + 1;
                        TrimSpace(filename);
                        commandline_buffer[end] = 0;
                        break;
                }else if(commandline_buffer[end] == '>'){
                        if(commandline_buffer[end - 1] == '>'){
                                redir = AppRedir;
                                commandline_buffer[end] = 0;
                                commandline_buffer[end - 1] = 0;
                                filename = &commandline_buffer[end] + 1;
                                TrimSpace(filename);
                                break;
                        }else{
                                redir = OutRedir;
                                commandline_buffer[end] = 0;
                                filename = &commandline_buffer[end] + 1;
                                TrimSpace(filename);
                                break;
                        }
                }else{
                        end--;
                }
        }
//......
}

2   总结

(1)文件描述符的概念,文件也是要被管理的(= 内容 + 属性),分为未打开的和被打开的
(2)标准输入输出错误之间的关系,以及系统调用接口open, close, read, write,文件流封装的底层一定有文件描述符
(3)文件描述符分配规则、012,重定向概念、原理、操作、如何进行
(4)内核角度理解“一切皆文件”,通过 struct file 对象和函数指针表屏蔽差异
(5)一个进程有自己的PCB,也要有自己打开的文件描述符表,还要有自己打开的工作文件,每个文件都要配备操作表、属性集和内核级缓冲区


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

相关文章:

  • 【深度学习基础】多层感知机 | 权重衰减
  • 构建高效稳定的网络环境
  • github登录用的TOTP和恢复码都丢失了怎么办
  • c++常见设计模式之装饰器模式
  • 顺序表和链表(详解)
  • 将UI界面交给第三方库
  • 链式设计及设计模式的应用
  • application.yml 和 bootstrap.yml
  • 坚果投影仪J10如何用苹果Siri开关机并和米家联动
  • 一、Origin绘制柱状图
  • 23种设计模式之解释器模式
  • 【PlantUML系列】状态图(六)
  • 2-2-18-14 QNX系统架构之 TCP/IP 网络
  • 保护数字资产:iOS 加固在当前安全环境中的重要性
  • ChatGPT Pro是什么
  • 【机器人】系统辨识之激励轨迹设计(傅里叶级数)
  • 原生微信小程序使用原子化tailwindcss
  • 阿里云负载均衡SLB实践
  • 在 Ubuntu 18.04 上使用 Snort 的完整攻略
  • LVGL9 开关控件 (lv_switch) 使用指南
  • java+ssm+mysql水产品商城
  • 重读《人月神话》(17)-没有银弹-软件工程中的根本和次要问题
  • C/C++ 堆和优先队列
  • 深度剖析 K 近邻算法:分类、回归实战及优劣势分析
  • 电脑启动过程
  • okHttp的tcp连接池的复用