Linux 基础IO(上)
目录
前言
重谈文件
文件操作
1.打开和关闭
2.对文件打开之后操作
理解文件fd
1.文件fd的分配规则与重定向
2.理解shell中的重定向
3.关于Linux下一切皆文件
关于缓冲区
1.为什么要有缓冲区
2.缓冲区刷新策略的问题
3.缓冲区的位置
前言
本篇到了我们linux中的文件部分,是我们文件部分的第一篇,再通过往后几篇内容,大家可以把我们之前在c语言中学过的文件操作与linux下文件部分联系起来,并且也能加深我们对于系统中文件的理解!!
重谈文件
1.空文件也要在磁盘占据空间
2.文件 = 内容 + 属性
3.文件操作 = 对内容 + 对属性 or 对内容和属性
4.标定一个文件,必须使用:文件路径 + 文件名(具有唯一性)
5.如果没有指明对应的文件路径,默认是在当前路径进行文件访问
6.当我们把fopen,fclose,fread,fwrite等接口写完之后,代码编译之后,形成可执行程序之后,但是没有运行,文件对应的操作有没有被执行呢? 答:没有被执行——对文件的操作本质:进程对文件的操作
7.一个文件要被访问,就必须要被先打开(被用户进程+操作系统打开)
是不是所有磁盘上的文件都被打开了?答:不是
a.被打开的文件
b.没有被打开的文件(在文件系统时会谈)
所以,文件操作的本质:进程 和 被打开文件 的关系
小tip:vim批量化注释:esc界面,ctrl+v之后,j下拉选择代码,输入大写i,再输入//,按esc就注释了所选行;取消按u
文件操作
1.打开和关闭
先了解一下标记位传参
了解了flags这样的构成之后,我们看在系统层面是用open来打开文件
open函数的三个参数
参数1:要打开的文件
参数2:flags也就是相应的标记位(只读/只写/读写)(使用不同的比特位来表示不同的含义)
参数3:要给文件的权限
失败返回-1
系统层面使用close配open来关闭文件
注意:如果我们用open传第二个参数时只传了读写的标记位,如果当前没有这个文件,在运行这个文件操作的程序时,会提示说没有该文件,在c层面会自动帮我们创建文件是因为它封装时添加了这个功能,我们要想在open这里让它自动创建文件得在该标记位后再加一个标记位|O_CREAT
但是看到这里我们这样来操作创建的文件是标红的,看前面的权限是混乱的,所以这里我们要传第三个参数来设置文件的默认权限
[^] 目录起始权限777,普通文件666
但是看这里的权限和我们给的是对应不上的,因为我们系统给的默认掩码umask是0022,也就是让设置的权限&(~umask)之后得到的才是文件的权限,如果不想这样,可以通过umask函数将子进程执行时的系统掩码设置为0
[^] 现在就是我们自己设置的权限
2.对文件打开之后操作
1.写文件
我们在系统层面就这一个写的函数
第一个参数:要写入的文件
第二个参数:想写的时候对应的缓冲区数据在哪里(操作系统看来都是二进制)
第三个参数:缓冲区当中的字节个数
返回值就是我们写了几个字节(在网络那边比较常见)
我们说以w方式单纯的打开文件,c会自动清空内部的数据 ,但是在系统层面可不会自动清空文件的数据,所以这样如果我们想两次写入不同的内容,覆盖清理会不完全,所以在open打开函数那里的第二个参数还得传一个标记位——O_TRUNC
将O_TRUNC改为O_APPEND为追加
2.读文件
以读的方式打开文件需要open第二个参数传O_RDONLY
读取函数read()
[^]: ssize_t为系统定制的类型,是有符号整数,可以>/</=0
第二个参数是读到哪个缓冲区
第三个参数是要读多少个到缓冲区
成功会返回自己读到了多少个字节,0表明读到了文件结尾
总结:
fopen fclose fwrite fread fseek ——库函数接口(封装了系统调用接口)
open close write read lseek ——系统调用接口
理解文件fd
fd为文件描述符
回答a
三个标准输入输出流:
stdin —— 键盘
stdout —— 显示器
stderr ——显示器
FILE是结构体,其中必定有一个字段——文件描述符
所以取出来它们分别是0,1,2,被占用了,所以我们自己的文件描述符是从3开始的
回答B
文件描述符的本质就是数组的下标
操作系统内标定进程和文件之间的关系用的就是文件描述符表,用数组来标定文件内容
1.文件fd的分配规则与重定向
从小到大按照顺序寻找最小的且没有被占用的fd
所以如果我们先把0这个位置文件关掉,那么我们下面创建一个文件时所占的文件描述符是0
我们在关闭fd为2的时候也是和上面一样,可当我们关闭fd为1的文件时,结果却没有打印,是什么原因?
因为我们的printf是输出到标准输入中的,可现在fd为1的位置的stdout被我们关掉了,现在是被我们写的文件占用,所以没法显示,但是如果我们在下面用fflush(stdout)刷新缓冲区,那么就会在我们的文件中看到我们打印的内容,因为此时的1是被我们的文件占用,自然刷新之后就可以在我们的文件中找到
我们把上面这种特性叫做重定向
c重定向的本质:上层用的fd不变,在内核中更改fd对应的struct file*的地址
我们有没有什么方法直接重定向呢?
[^]: 头文件为:#include<unistd.h>>
用dup2函数将一个文件描述符对应文件的内容拷贝到另一个文件描述符对应的文件中
所以如何直接重定向,让1指向我们的文件呢?
答:我们需要把fd中的内容拷贝到1中,也就是dup2(fd,1);
追加重定向和dup2没有关系,和文件描述符表里面的内容做修改没有关系,只和打开文件的方式有关
输入重定向:让我们不从键盘上读取内容,而是到我们的文件中去读取
dup2(fd,0);
2.理解shell中的重定向
(> 输出重定向 >>追加 <输入重定向)
1.执行程序替换的时候,会不会影响曾经进程打开的重定向的文件?
答:不会,替换的是数据和代码,和内核数据结构没关系
如果我们的父进程删除了这个文件,或者是子进程把文件关掉了,是不是父进程就访问不了了?
答:不会,因为一个被打开文件的里面包含了引用计数,指向文件时会让count++,表示有几个指针指向文件,关闭文件其实是让count--,我们close文件其实操作系统做的是让count--,而不是真正的关闭释放文件,我们打开文件其实是让count++
3.关于Linux下一切皆文件
这就是多态的体现!
关于缓冲区
先来看个问题:
可以从上图中看到c接口的函数都被打印了两次,系统接口前后都只是被打印了一次
经过测试,这与fork()函数有关,也和缓冲区有关
1.为什么要有缓冲区
缓冲区的本质:就是一段内存,是内存的一部分
缓冲区的意义:
要把进程的数据拷贝到缓冲区,fwrite这个函数,与其理解为是写入到文件的函数,倒不如理解成是拷贝函数:将数据从进程拷贝到“缓冲区”或者外设中
2.缓冲区刷新策略的问题
如果有一块数据,一次性写入到外设(效率最高)vs 多次少批量写入外设
缓冲区一定会结合具体的设备,定制自己的刷新策略:
a. 立即刷新——无缓冲
b. 行刷新——行缓存——显示器
c. 缓冲区满再刷新——全缓冲——磁盘文件 (效率最高)
两种特殊情况:
1.用户强制刷新
2.进程退出—— 一般都要进行缓冲区刷新
3.缓冲区的位置
从上面的问题的图片可以看到,缓冲区一定不在内核中,因为如果在内核中,write也应该打印两次,所以我们之前谈论的所有缓冲区,都指的是用户级语言层面给我们提供的缓冲区
这个缓冲区在stdout、stdin、stderr的类型FILE*这个结构体中(不仅包含fd,还包括一个缓冲区),所以我们要自己强制刷新时的fflush(文件指针),以及关闭文件时的fclose(文件指针)都要传一个文件指针,都是因为这些文件指针内包含了内部的缓冲区
关于FILE
所以此时我们可以解决一开始的fork()之后重定向三个c语言接口重复打印两次的问题:
代码结束之前,进行创建子进程
-
如果我们没有进行>,就只会看到4条打印的信息 ,是因为stdout默认使用的是行刷新,在进程fork之前,三条C函数已经将数据进行打印输出到显示器上(外设),你的FILE内部,进程内部不存在对应的数据啦
-
如果我们进行了>, 写入文件不再是显示器,而是普通文件,采用的刷新策略是全缓冲,之前的3条c显示函数,虽然带了\n,但是不足以让stdout缓冲区写满,数据并没有被刷新!!! 当我们执行fork的时候,stdout属于父进程,创建子进程时, 紧接着就是进程退出! 谁先退出,就一定要进行缓冲区刷新(就是修改) ,发生了写时拷贝!!!数据最终会显示两份
-
write为什么没有呢?上面的过程都和wirte无关,wirte没有FILE,而用的是fd,就没有C提供的缓冲区
缓冲区和操作系统的关系,我们在C语言封装的接口中要拷贝到缓冲区一次,到os中也要拷贝一次到内核缓冲区中,并且操作系统的刷新策略更复杂
os完全自主决定刷新数据出缓冲区的时机,如果os宕机了,数据要是还没更新出去就会导致数据丢失,如果是在银行这种对数据丢失0容忍的地方肯定是不行的
所以我们可以在用户层告知操作系统强制将对应的该文件的内核缓冲区的数据更新到磁盘上
c++的文件IO流也是一样的,是一个类,其中也要包含缓冲区和文件描述符(fd)
尾声
本篇发布时正好是端午节,那就祝大家端午节快乐!\^o^/
相关文章:

Linux 基础IO(上)
目录 前言 重谈文件 文件操作 1.打开和关闭 2.对文件打开之后操作 理解文件fd 1.文件fd的分配规则与重定向 2.理解shell中的重定向 3.关于Linux下一切皆文件 关于缓冲区 1.为什么要有缓冲区 2.缓冲区刷新策略的问题 3.缓冲区的位置 前言 本篇到了我们linux中的文件…...
如何加载私钥为 SecKeyRef
本文介绍如何在 iOS/macOS 下将私钥加载为 SecKeyRef,涵盖 PEM 格式的 ECC 密钥读取、X9.63 数据构建、以及与 Keychain 的集成。 1. 使用 SecKeyCreateWithData 加载私钥 Apple 提供的 SecKeyCreateWithData 方法可以直接将密钥数据加载为 SecKeyRef 对象。 SecK…...
@Pushgateway自定义脚本推送数据
文章目录 Pushgateway 自定义脚本推送数据1. 目的2. 适用范围3. 前提条件4. 操作流程4.1 确定指标类型和格式4.2 编写推送脚本方法一:使用 curl 命令行推送方法二:使用 Python 脚本推送方法三:使用 Python 客户端库推送4.3 设置定时任务4.4 验证数据5. 高级配置5.1 使用基本…...
kubernate解决 “cni0“ already has an IP address different from 10.244.0.1/24问题
问题 NetworkPlugin cni failed to set up pod “coredns-5d4b4db-jkmnl_kube-system” network: failed to set bridge addr: “cni0” already has an IP address different from 10.244.0.1/24 解决方案 这个问题通常是由于Flannel网络插件残留配置导致的IP地址冲突。以下…...

el-tree拖拽事件,限制同级拖拽,获取拖拽后节点的前后节点,同级拖拽合并父节点name且子节点加入目标节点里
node-drag-start:开始拖拽节点时触发(按下鼠标按钮),无论是否允许放置,此事件都会触发。 allow-drop 返回 true 才能触发@node-drag-end="handleDragend"、@node-drop="handleDrop"; (1)allow-drop:动态控制是否允许放置; (2)node-dr…...

day62—DFS—太平洋大西洋水流问题(LeetCode-417)
题目描述 有一个 m n 的矩形岛屿,与 太平洋 和 大西洋 相邻。 “太平洋” 处于大陆的左边界和上边界,而 “大西洋” 处于大陆的右边界和下边界。 这个岛被分割成一个由若干方形单元格组成的网格。给定一个 m x n 的整数矩阵 heights , hei…...

《Python基础》第2期:环境搭建
在开始编写 Python 代码前,还需要搭建 Python 的开发环境。 电脑是没办法直接读懂 Python 代码的,而是需要一个解释器,实时把代码翻译成字节码,字节码再转换成 0 和 1,电脑就能读懂了。 Python 的运行过程就是翻译一行…...

WSL 安装 Debian 12 后,Linux 如何安装 curl , quickjs ?
在 WSL 的 Debian 12 系统中安装 curl 非常简单,你可以直接使用 APT 包管理器从官方仓库安装。以下是详细步骤: 1. 更新软件包索引 首先确保系统的包索引是最新的: sudo apt update2. 安装 curl 执行以下命令安装 curl: sudo…...

[CSS3]vw/vh移动适配
vw/vh 目标: 能够使用vw单位设置网页元素的尺寸 相对单位相对视口的尺寸计算结果.vw全称viewport width; 1vw1/100视口宽度 vh全称viewport height; 1vh1/100视口高度 体验vw和vh单位 <!DOCTYPE html> <html lang"en"> <head><meta charset…...
Python进阶与常用库:探索高效编程的奥秘
一、文件与目录操作:os模块 os模块是Python标准库中用于与操作系统交互的核心工具,提供了丰富的文件和目录操作方法。通过os,开发者可以轻松实现文件路径处理、环境变量获取、目录管理等功能。 1.1 核心功能与方法 以下是os模块中常用的方…...
nt!MiDispatchFault函数分析之nt!MiCompleteProtoPteFault函数的作用
nt!MiDispatchFault函数分析之nt!MiCompleteProtoPteFault函数的作用 第一部分: // // PTE is still in transition state, same protection, etc. // ASSERT (Pfn1->u4.InPageError 0); if (Pfn1->u2.ShareCount 0) { MI_REMO…...

YOLOX 的动态标签分类(如 SimOTA)与 Anchor-free 机制解析2025.5.29
YOLOX 的动态标签分类(如 SimOTA)与 Anchor-free 机制是其核心改进中的两个关键部分,它们在目标检测中的作用和实现方式存在显著差异。以下从原理、实现细节及效果三个方面进行详细对比: 一、核心原理与目标 1. Anchor-free 机制…...
打卡day42
DAY 42 Grad-CAM与Hook函数 知识点回顾 回调函数lambda函数hook函数的模块钩子和张量钩子Grad-CAM的示例 作业:理解下今天的代码即可 1、回调函数 回调函数(Callback Function)是一种特殊的函数,它作为参数传递给另一个函数&am…...
小白的进阶之路系列之八----人工智能从初步到精通pytorch综合运用的讲解第一部分
PyTorch Tensors 通过大量实例学习编程应用是最有效的方法。 本篇是PyTorch综合运用,旨在让读者通过一行行代码亲自掌握Pytorch工具包的各种功能,有利于大家部署自己的神经网络人工智能计算工程。 首先,载入torch库。 import torch我们来看看一些基本的张量操作。首先,…...

724.寻找数组的中心下标前缀和
题目链接: https://leetcode.cn/problems/find-pivot-index/ 这道题目我们可以使用暴力解法,就一个下标前数组之和,再求一个下标后数组之和,时间复杂度达到n方,我们来写一下: int pivotIndex(vector<in…...

软考-系统架构设计师-第十六章 层次式架构设计理论与实践
层次式架构设计理论与实践 16.2 表现层框架设计16.3 中间层框架设计16.4 数据访问层设计16.5 数据架构规划与设计16.6 物联网层次架构设计 软件体系结构为软件系统提供了结构、行为和属性的高级抽象,由构成系统的元素描述这些元素的相互作用、指导元素集成的模式以及…...
甘特图 dhtmlxGantt.js UA实例
摘要:本文介绍了一个基于AngularJS的排产资源占用甘特图系统,包含前端界面展示和后端控制逻辑。系统通过HTML模板实现甘特图展示区域、查询条件表单和数据绑定,使用JavaScript控制器处理数据查询、甘特图初始化和交互逻辑。主要功能包括&…...

Docker学习笔记:基础知识
本文是自己的学习笔记 1、什么是Docker2、Docker的架构设计2.1、镜像(Image)2.2、容器(Container)2.3、仓库(Repository)2.4、Docker使用场景案例 1、什么是Docker Docker是基于Go语言实现的云开源项目。它的角色是作…...

5.2 初识Spark Streaming
在本节实战中,我们初步探索了Spark Streaming,它是Spark的流式数据处理子框架,具备高吞吐量、可伸缩性和强容错能力。我们了解了Spark Streaming的基本概念和运行原理,并通过两个案例演示了如何利用Spark Streaming实现词频统计。…...
uv:一个现代化的 Python 依赖管理工具
在 Python 的生态系统中,依赖管理和 Python 版本管理一直是开发者关注的核心问题。传统的工具如 pip、poetry 和 pyenv 虽然功能强大,但在性能和使用体验上仍有改进空间。uv 是由 Python 核心开发者开发的 现代化依赖管理工具,旨在提供更快、…...

Python趣学篇:交互式词云生成器(jieba + Tkinter + WordCloud等)
名人说:路漫漫其修远兮,吾将上下而求索。—— 屈原《离骚》 创作者:Code_流苏(CSDN)(一个喜欢古诗词和编程的Coder😊) 目录 一、为什么要做词云?让文字"活"起来!二、核心…...

理解解释器架构:原理、组成与运行机制全解析
目录 前言1. 什么是解释器架构2. 解释器的基本组成2.1 被解释执行的程序2.2 解释器引擎2.3 解释器内部状态2.4 程序执行的当前状态2.5 存储器模型 3. 解释器的工作原理3.1 解析源代码3.2 初始化运行环境3.3 逐条执行语法结构3.4 维护程序状态3.5 内存管理与变量作用域 4. 举例&…...

2025华为OD机试真题+全流程解析+备考攻略+经验分享+Java/python/JavaScript/C++/C/GO六种语言最佳实现
华为OD全流程解析,备考攻略 快捷目录 华为OD全流程解析,备考攻略一、什么是华为OD?二、什么是华为OD机试?三、华为OD面试流程四、华为OD薪资待遇及职级体系五、ABCDE卷类型及特点六、题型与考点七、机试备考策略八、薪资与转正九、…...
Python应用for循环临时变量作用域
大家好!如果你刚开始学习Python,可能会对for循环中临时变量的作用域感到好奇。下面通过一个简单的练习,帮助你理解这个概念。 代码呈现: i 0 for i in range(5):print(i)print(i)代码介绍: 首先我们初始化变量i 0然后进入for循环,这里i成为…...

设计模式——桥接设计模式(结构型)
摘要 桥接设计模式是一种结构型设计模式,用于将抽象与实现解耦,使二者可以独立变化。它通过将一个类拆分为“抽象”和“实现”两部分,并通过桥接关系组合,避免了类继承层次结构过于庞大。桥接模式包含抽象类、扩充抽象类、实现类…...

LLaDa——基于 Diffusion 的大语言模型 打平 LLama 3
这里分享一篇文章《Large Language Diffusion Models》,来自人民大学高领人工智能学院,一篇尝试改变传统自回归范(预测下一个token) LLM 架构,探索扩散模型在 LLM 上的作用,通过随机掩码-预测逆向思维&…...
Apache SeaTunnel部署技术详解:模式选择、技巧与最佳实践
Apache SeaTunnel(原Waterdrop)作为高性能、分布式数据集成平台,支持海量数据的离线与实时同步。其灵活多样的部署模式可适配不同规模的生产环境需求。本文将系统解析SeaTunnel的部署架构、技术要点及最佳实践,帮助用户高效构建稳…...

2. 数据结构基本概念 (2)
本文部分ppt、视频截图来自:[青岛大学-王卓老师的个人空间-王卓老师个人主页-哔哩哔哩视频] 1. 数据结构基本概念 1.1 数据类型和抽象数据类型 (1) 数据类型(Data Type) 概念 数据类型是一组性质相同的值的集合以及定义于这个值集合上的一组操作的总称。 在使用…...
鸿蒙5.0+ 多协议设备发现与分布式软总线技术实践
一、技术演进与架构升级 1.1 多协议发现机制演进 鸿蒙5.0重构设备发现层,支持三模异构发现: 经典蓝牙(BLE 5.2):低功耗设备发现Wi-Fi Aware:高带宽设备预连接PLC࿰…...

STM32F407寄存器操作(多通道单ADC+DMA)
1.前言 又是半年没更新了,趁着端午放假有点时间,并且最近项目要用这块知识,我就顺带研究一下ADC吧。 一般来说ADC主要用法包含了1.单通道软件触发(这是最简单和最常用的用法)2.单通道多次采集(需要快速采…...