【Linux 文件读写描述符重定向 Linux 一切皆文件缓冲区】

文章目录

  • 一、文件的读写操作
  • 二、文件描述符
  • 三、文件重定向
  • 四、理解 Linux 一切皆文件
  • 五、文件缓冲区

一、文件的读写操作

文件=内容+属性
当文件没有被操作的时候,一般文件还是在磁盘当中
文件操作=文件内容的操作+文件属性的操作,文件操作有可能即改变内容,又改变属性
文件操作其实就是把内容和属性加载到内存当中

  文件的系统调用函数一般有以下几个参数,pathname(对应文件路径),flags(文件打开方式),mode(指定文件的权限)。这里的 flags 不能简单当作一个整型来看,而且应该把它当作一个位图,32个 bit 位对应32种状态。打开文件时,可以传入多个参数选项,用下面的一个或者多个宏进行 “或” 运算,构成flags,调用类似下面的 show(ONE | TWO | THREE)

int open(const char *pathname, int flags);
int open(const char *pathname, int flags, mode_t mode);
flags参数:
O_RDONLY: 只读打开
O_WRONLY: 只写打开
O_RDWR : 读,写打开
这三个常量,必须指定一个且只能指定一个
O_CREAT : 若文件不存在,则创建它。需要使用mode选项,来指明新文件的访问权限
O_TRUNC:初始化清空文件
O_APPEND: 追加写

#define ONE (1<<0)   // 1                                                                                                                  
#define TWO (1<<1)   // 2  
#define THREE (1<<2) // 4  
#define FOUR (1<<3)  // 8 
void show(int flags)  
{  
    if(flags&ONE) printf("func1\n");  
    if(flags&TWO) printf("func2\n");  
    if(flags&THREE) printf("func3\n");  
    if(flags&FOUR) printf("func4\n");  
    //………
} 

  文件操作其实就是一系列的系统调用,调用系统提供的函数。就算是语言层面的操作文件函数,也只是在内部封装了 open、write、read 等系统函数。因为IO相关函数与系统调用接口对应,并且库函数封装系统调用,所以本质上,访问文件都是通过 fd(文件描述符) 访问的。所以C库当中的 FILE 结构体内部,必定封装了 fdC/C++ 封装的库函数中对文件打开方式主要有以下几种:

FILE * fopen ( const char * filename, const char * mode )
mode参数:
b:以二进制模式打开文件
r&r+:前者以只读方式打开,后者以读写方式打开文件.文件必须存在,否则打开失败
w&w+:前者以写入方式打开,后者以读写方式打开文件.若文件不存在,则创建新文件。存在,则清空文件内容
a: 以追加写入方式打开文件,若文件不存在,则创建新文件。写入的数据总是添加到文件的末尾
a+:以读写追加方式打开文件,若文件不存在,则创建新文件。可以从文件的任何位置读取数据,写入的数据总是添加到文件的末尾

二、文件描述符

  要对文件进行系统的管理,必须先描述再组织。当一个进程打开一个文件时,内核会创建一个 struct file 结构来存储关于这个文件的所有信息,包括:

文件在磁盘上的位置;文件的基本属性,如权限、大小;
文件的读写位置(文件偏移量);
文件的拥有者信息,即哪个进程打开了该文件;
文件的内核缓冲区信息等;

  task_struct 结构体里面的成员:struct files_struct,用于管理一个进程打开的所有文件。它包含: 一个文件描述符表 fd_array,这是一个数组,其元素是指向 struct file 的指针,每个元素对应一个打开的文件。文件描述符(FD)是这个数组的索引,每个索引唯一地标识了一个打开的文件。文件描述符是一个非负整数,0,1,2默认被占用为标准输入,标准输出和标准错误三个文件,即我们创建文件的描述符都是从3以后开始。当进程关闭文件时,会减少 struct file 的引用计数。如果引用计数变为0,内核会释放 struct file 实例,并清理相关资源。

文件的简单管理结构如下:

三、文件重定向

  文件重定向的本质是修改文件描述符表 fd_array 中的 FD 对应的 struct file* 地址。即文件描述符 FD(0,1,2,3) 等不变,改变 struct file* 的值,使它指向不同的文件

dup2 系统调用实现重定向:

#include <unistd.h>
int dup2(int oldfd, int newfd);

  dup2 函数的作用是将 oldfd 指向的文件地址覆盖 newfd 指向的文件地址,如果 newfd 指向的文件已经打开,则会先关闭 newfddup2 函数可以使不同文件描述符可以指向同一个文件,如下图:

四、理解 Linux 一切皆文件

  操作系统是一款管理软件,它通过向下管理好各种软硬件资源 (手段),来向上提供良好 (安全、稳定、高效) 的运行环境 (目的)。对键盘、显示器、磁盘、网卡等硬件进行管理需要先描述、再组织:即先将这些设备的各种属性抽象出来组成一个结构体,然后为每一个设备都创建一个结构体对象,再用某种数据结构将这些对象组织起来,这也就是我们上面学习到的文件内核数据结构 file
  由于每种硬件的访问方法都是不一样的,我们需要为每一种硬件都单独提供对应的 Read、Write 等方法,这些方法位于驱动层。参考下图:
  struct file 中定义函数指针 read()write() 方法 ,而这些方法在驱动层被实例化,指向不同硬件的访问方法。这是一种多态行为。即使用户使用相同的系统调用接口,实际执行的操作会根据底层文件或设备的类型而变化。file 结构体可以类似于 C++ 中的基类,驱动层的各种方法和结构就相当于子类,可以看作它们继承了基类,同时又扩充了对底层硬件管理的特殊方法。站在操作系统内核数据结构上层来看,所有的软硬件设备和文件统一都是 file 对象,它是操作系统当中虚拟出来的一层文件对象,我们将这一层称为 虚拟文件系统 VFS,通过它,我们就可以摒弃掉底层设备的差别,统一使用文件接口的方式来进行文件操作,即 Linux 下一切皆文件!

五、文件缓冲区

  缓冲区分为用户级缓冲区和内核级缓存区,我们所接触到的缓冲区大部分都属于用户级语言缓冲区。文件也有自己的缓冲区,被描述为 FILE 结构体中的一个字段,类似 char buff [size]。而我们常说的刷新缓冲区就是指缓冲区里的数据加载(拷贝)到内核缓冲区,而文件是被进程管理的,进程退出时与文件描述符相关联的内核缓冲区会被刷新到磁盘上。
缓冲区刷新常见策略:

1、无缓冲(立即刷新) :缓冲区中一出现数据就立马刷新,这种很少出现;
2、行缓冲(行刷新 ):遇到换行符(\n)数据就刷新一次
3、全缓冲(缓冲区满刷新):待数据把缓冲区填满后再刷新,这种刷新方式效率最高,一般应用于磁盘文件

  显示器采用的刷新策略是行缓冲,与此相对,普通文件采用的刷新策略是全缓冲。显示器是给人看的,按行刷新符合人的阅读习惯,而普通文件更多需要全缓存来提高效率。
  系统调用接口 write 是直接往内核缓存区里写,如 C库中的 fwrite 是往文件缓冲区里面写,当文件缓冲区刷新时,再把文件缓冲区里的数据加载(拷贝)到内核缓冲区。下面通过两个例子来加深对缓冲区的理解;

例一:
  两张图片中都关闭了1号标准输出文件,但是左图把信息全部打印出来了,而右图只打印了系统调用 write,因为显示器文件是行刷新,左图 fwrite 加了换行符 \n的信息已经从文件缓冲区拷贝到了内核缓冲区,被显示出来。而右图没有加换行符 \n,关闭了文件描述符后,文件缓冲区的信息没有加载到内核缓冲区中,因此右边的 fwrite 信息消失不见。write 系统调用是直接往内核缓冲区写的,因此左右图都会打印 write 信息


例二:
  由上面我们知道,文件缓冲区被描述为 FILE 结构体中的一个字段,那么当我们 fork 创建子进程时,子进程会拥和父进程一样的文件描述符表及其缓冲区。当我们向显示器打印时,按行刷新。fork 时,此时父进程的文件缓冲区为空,信息已经刷新到了内核缓冲区中。此时子进程虽然拥有和父进程一样的文件缓冲区,但却是空的,因此显示结果如左边。当我们重定向到普通文件打印时,为全缓冲,fork 时,父进程文件缓冲区有 fwrite 信息,因此 fork 之后子进程的文件缓冲区也有 fwrite 信息,最终导致 fwrite 打印了两次,而 write 打印在前面是因为它直接写入了内核缓冲区,不用像 fwrite 一样刷新了才加载到内核缓冲区

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/797684.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

最新版智能修图-中文luminar ai 1.55(13797) 和 neo1.20,支持m芯片和intel芯片(绝对可用)

Luminar AI for macOS 完整版本 这个程序是第一个完全由人工智能驱动的图像编辑器。有了它&#xff0c;创建引人注目的照片是有趣的&#xff0c;令人惊讶的容易。它是一个独立的照片编辑器和macOS插件。 Luminar AI for macOS 轻轻地塑造和完善一个肖像打造富有表现力的眼睛…

Arduino PID整定

Arduino PID整定 Tuning an Arduino PID Introduction to Tuning an Arduino PID 例如&#xff0c;我们可能想把一箱水加热到华氏 100 度。 我们需要能够在不同的条件下实现这一目标&#xff0c;例如房间的环境&#xff08;周围&#xff09;温度。 此外&#xff0c;我们可能会…

WPF学习(6) -- WPF命令和通知

一 、WPF命令 1.ICommand代码 创建一个文件夹和文件 using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Input;namespace 学习.Command {public class MyCommand : ICommand{Acti…

无损音乐播放器推荐:Audirvana for Mac 中文激活版

udirvana 是一款高品质的音乐播放软件&#xff0c;专为Mac操作系统设计。它被设计来提供音频播放的最高标准&#xff0c;支持多种音频格式&#xff0c;包括高达32位/192kHz的高分辨率音频。Audirvana Plus 是其高级版本&#xff0c;提供了更多的功能和优化&#xff0c;例如音频…

LabVIEW远程实验数据采集系统

随着科学研究的不断发展&#xff0c;实验室对远程数据采集和监控的需求越来越高。传统的数据采集方式往往需要实验人员亲临现场&#xff0c;费时费力&#xff0c;且数据实时性较差。为了解决这些问题&#xff0c;基于LabVIEW开发了一套远程实验数据采集系统&#xff0c;实现对实…

【深度学习入门篇 ⑤ 】PyTorch网络模型创建

【&#x1f34a;易编橙&#xff1a;一个帮助编程小伙伴少走弯路的终身成长社群&#x1f34a;】 大家好&#xff0c;我是小森( &#xfe61;ˆoˆ&#xfe61; ) &#xff01; 易编橙终身成长社群创始团队嘉宾&#xff0c;橙似锦计划领衔成员、阿里云专家博主、腾讯云内容共创官…

0/1背包

0/1背包 背包问题是DP最经典的类型之一&#xff0c;而0/1背包是最经典最基础的背包问题。 一个背包体积为 v v v&#xff0c;现有 n n n种物品&#xff0c;第 i i i个物品对应体积为 c i c_i ci​&#xff0c;价值为 w i w_i wi​&#xff0c;每件物品最多可放1次&#xff0c;…

初识影刀:EXCEL根据部门筛选低值易耗品

第一次知道这个办公自动化的软件还是在招聘网站上&#xff0c;了解之后发现对于办公中重复性的工作还是挺有帮助的&#xff0c;特别是那些操作非EXCEL的重复性工作&#xff0c;当然用在EXCEL上更加方便&#xff0c;有些操作比写VBA便捷。 下面就是一个了解基本操作后&#xff…

如何追踪ping连接中的所有路由器的数量和IP

如何快速判断ping连接经过的路由器个数和IP&#xff1f; 方法一&#xff1a; ping命令会返回一个TTL&#xff0c;TTL&#xff08;Time To Live&#xff09;存活时间&#xff0c;一般初始值为64&#xff0c;每经过一个路由器就减一&#xff0c;当TTL为0时丢弃网络包&#xff0…

【深度学习】PyTorch深度学习笔记01-Overview

参考学习&#xff1a;B站视频【《PyTorch深度学习实践》完结合集】-刘二大人 ------------------------------------------------------------------------------------------------------- 1. 基于规则的深度学习 2. 经典的机器学习——手动提取一些简单的特征 3. 表示学习…

Linux问题解决

1、打开VMware Workstation&#xff0c;开启需要安装VMware Tools的虚拟机&#xff0c;在顶部选择菜单栏的虚拟机选项卡&#xff0c;点击“安装VMware Tools(T&#xff09;”。 或者有时在底部会弹出提示框安装tools&#xff0c;点击安装也可以。 2、进入ubuntu系统后&#xff…

《Linux系统编程篇》vim的使用 ——基础篇

引言 上节课我们讲了&#xff0c;如何将虚拟机的用户目录映射到自己windows的z盘&#xff0c;虽然这样之后我们可以用自己的编译器比如说Visual Studio Code&#xff0c;或者其他方式去操作里面的文件&#xff0c;但是这是可搭建的情况下&#xff0c;在一些特殊情况下&#xf…

【Linux】数据流重定向

数据流重定向&#xff08;redirect&#xff09;由字面上的意思来看&#xff0c;好像就是将【数据给它定向到其他地方去】的样子&#xff1f; 没错&#xff0c;数据流重定向就是将某个命令执行后应该要出现在屏幕上的数据&#xff0c;给它传输到其他的地方&#xff0c;例如文件或…

4G LTE 教程 物理通道结构

https://www.artizanetworks.com/resources/tutorials/phy_cha.html 下行物理信道&#xff1a; 物理下行链路共享信道 (PDSCH) 承载 DL-SCH 和 PCH。DL-SCH 包含实际用户数据。物理下行链路控制信道 (PDCCH) 通知UEPCH和DL-SCH的资源分配情况&#xff0c;以及DL-SCH相关的HARQ…

tongweb8 使用命令行对应用进行操作(by lqw)

文章目录 声明思路和概念新增应用更新应用启动应用停止应用删除应用 声明 本帖只是做一些简单的应用查看&#xff0c;新增&#xff0c;启动&#xff0c;停止&#xff0c;删除操作&#xff0c;仅供参考&#xff0c;详细内容建议参考TongwebV8.0 命令行工具参考&#xff0c;生产…

InjectFix 热更新解决方案

简介 今天来谈一谈&#xff0c;项目种的客户端热更新解决方案。InjectFix是腾讯xlua团队出品的一种用于Unity中C#代码热更新热修复的解决方案。支持Unity全系列&#xff0c;全平台。与xlua的思路类似&#xff0c;InjectFix解决的痛点主要在于Unity中C#代码写的逻辑在发包之后无…

Python爬虫:基础爬虫架构及爬取证券之星全站行情数据!

爬虫成长之路&#xff08;一&#xff09;里我们介绍了如何爬取证券之星网站上所有A股数据&#xff0c;主要涉及网页获取和页面解析的知识。爬虫成长之路&#xff08;二&#xff09;里我们介绍了如何获取代理IP并验证&#xff0c;涉及了多线程编程和数据存储的知识。此次我们将在…

深度学习LSTM之预测光伏发电

代码一&#xff1a;训练LSTM模型 代码逐段分析 import numpy as np import pandas as pd import tensorflow.keras as tk from tensorflow.keras import layers首先&#xff0c;导入了必要的库&#xff1a;numpy用于数值计算&#xff0c;pandas用于数据处理&#xff0c;tenso…

k8s record 20240710 监控

不是adaptor 是opetator 案例 监控有了&#xff0c;日志搜集呢&#xff1f; 一、kubelet 的小弟 kubelet — 负责维护容器的生命周期&#xff0c;节点和集群其他部分通信 cAdvisor 集成在 Kubernetes 的 kubelet 中&#xff0c;能够自动发现和监控集群中所有的容器。dockers…

尚硅谷Vue3入门到实战,最新版vue3+TypeScript前端开发教程

Vue3 编码规范 创建vue3工程 基于vite创建 快速上手 | Vue.js (vuejs.org) npm create vuelatest 在nodejs环境下运行进行创建 按提示进行创建 用vscode打开项目 安装依赖 源文件有src 内有main.ts App.vue 简单分析 编写src vue2语法在三中适用 vue2中的date metho…