Linux 基础IO(上)

article/2025/6/24 13:58:38

目录

前言

重谈文件

文件操作

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.没有被打开的文件(在文件系统时会谈)

所以,文件操作的本质:进程 和 被打开文件 的关系

image-20250530184902773

小tip:vim批量化注释:esc界面,ctrl+v之后,j下拉选择代码,输入大写i,再输入//,按esc就注释了所选行;取消按u

文件操作

1.打开和关闭

先了解一下标记位传参

image-20250502153434891

了解了flags这样的构成之后,我们看在系统层面是用open来打开文件

image-20250502153722743

open函数的三个参数

参数1:要打开的文件

参数2:flags也就是相应的标记位(只读/只写/读写)(使用不同的比特位来表示不同的含义)

image-20250502153922197

参数3:要给文件的权限

失败返回-1

系统层面使用close配open来关闭文件

image-20250502154412951

注意:如果我们用open传第二个参数时只传了读写的标记位,如果当前没有这个文件,在运行这个文件操作的程序时,会提示说没有该文件,在c层面会自动帮我们创建文件是因为它封装时添加了这个功能,我们要想在open这里让它自动创建文件得在该标记位后再加一个标记位|O_CREAT

image-20250502155702623

image-20250502155740856

image-20250502155901545

但是看到这里我们这样来操作创建的文件是标红的,看前面的权限是混乱的,所以这里我们要传第三个参数来设置文件的默认权限

image-20250502162522081

[^]  目录起始权限777,普通文件666 

image-20250502162600169

但是看这里的权限和我们给的是对应不上的,因为我们系统给的默认掩码umask是0022,也就是让设置的权限&(~umask)之后得到的才是文件的权限,如果不想这样,可以通过umask函数将子进程执行时的系统掩码设置为0

image-20250502163440306

image-20250502163603241

image-20250502163626833

[^]  现在就是我们自己设置的权限 

2.对文件打开之后操作

1.写文件

image-20250502164008887

我们在系统层面就这一个写的函数

第一个参数:要写入的文件

第二个参数:想写的时候对应的缓冲区数据在哪里(操作系统看来都是二进制)

第三个参数:缓冲区当中的字节个数

返回值就是我们写了几个字节(在网络那边比较常见)

我们说以w方式单纯的打开文件,c会自动清空内部的数据 ,但是在系统层面可不会自动清空文件的数据,所以这样如果我们想两次写入不同的内容,覆盖清理会不完全,所以在open打开函数那里的第二个参数还得传一个标记位——O_TRUNC

image-20250502172854935

将O_TRUNC改为O_APPEND为追加

2.读文件

以读的方式打开文件需要open第二个参数传O_RDONLY

读取函数read()

image-20250503105352036

[^]: ssize_t为系统定制的类型,是有符号整数,可以>/</=0

第二个参数是读到哪个缓冲区

第三个参数是要读多少个到缓冲区

成功会返回自己读到了多少个字节,0表明读到了文件结尾

image-20250503112617119

总结:

fopen fclose fwrite fread fseek ——库函数接口(封装了系统调用接口)

open close write read lseek ——系统调用接口

理解文件fd

fd为文件描述符

image-20250530184601823

image-20250503120956051

回答a

三个标准输入输出流:

stdin —— 键盘

stdout —— 显示器

stderr ——显示器

image-20250503121939168

FILE是结构体,其中必定有一个字段——文件描述符

所以取出来它们分别是0,1,2,被占用了,所以我们自己的文件描述符是从3开始的

image-20250503121931027

回答B

文件描述符的本质就是数组的下标

操作系统内标定进程和文件之间的关系用的就是文件描述符表,用数组来标定文件内容

image-20250503140825973

1.文件fd的分配规则与重定向

从小到大按照顺序寻找最小的且没有被占用的fd

image-20250505162913542

所以如果我们先把0这个位置文件关掉,那么我们下面创建一个文件时所占的文件描述符是0

image-20250505163238539

image-20250505163256651

我们在关闭fd为2的时候也是和上面一样,可当我们关闭fd为1的文件时,结果却没有打印,是什么原因?

image-20250531172230972

因为我们的printf是输出到标准输入中的,可现在fd为1的位置的stdout被我们关掉了,现在是被我们写的文件占用,所以没法显示,但是如果我们在下面用fflush(stdout)刷新缓冲区,那么就会在我们的文件中看到我们打印的内容,因为此时的1是被我们的文件占用,自然刷新之后就可以在我们的文件中找到

image-20250505210417230

我们把上面这种特性叫做重定向

c重定向的本质:上层用的fd不变,在内核中更改fd对应的struct file*的地址

我们有没有什么方法直接重定向呢?

image-20250505212121018

[^]: 头文件为:#include<unistd.h>>

用dup2函数将一个文件描述符对应文件的内容拷贝到另一个文件描述符对应的文件中

所以如何直接重定向,让1指向我们的文件呢?

答:我们需要把fd中的内容拷贝到1中,也就是dup2(fd,1);

image-20250505213754772

追加重定向和dup2没有关系,和文件描述符表里面的内容做修改没有关系,只和打开文件的方式有关

image-20250506094423399

输入重定向:让我们不从键盘上读取内容,而是到我们的文件中去读取

dup2(fd,0);

image-20250506095317415

2.理解shell中的重定向

(> 输出重定向 >>追加 <输入重定向)

1.执行程序替换的时候,会不会影响曾经进程打开的重定向的文件?

答:不会,替换的是数据和代码,和内核数据结构没关系

image-20250531171638946

如果我们的父进程删除了这个文件,或者是子进程把文件关掉了,是不是父进程就访问不了了?

答:不会,因为一个被打开文件的里面包含了引用计数,指向文件时会让count++,表示有几个指针指向文件,关闭文件其实是让count--,我们close文件其实操作系统做的是让count--,而不是真正的关闭释放文件,我们打开文件其实是让count++

image-20250506205747804

3.关于Linux下一切皆文件

这就是多态的体现!

image-20250506201604856

关于缓冲区

先来看个问题:

image-20250507101257032

image-20250507101321038

可以从上图中看到c接口的函数都被打印了两次,系统接口前后都只是被打印了一次

经过测试,这与fork()函数有关,也和缓冲区有关

1.为什么要有缓冲区

缓冲区的本质:就是一段内存,是内存的一部分

缓冲区的意义:

image-20250507115858081

要把进程的数据拷贝到缓冲区,fwrite这个函数,与其理解为是写入到文件的函数,倒不如理解成是拷贝函数:将数据从进程拷贝到“缓冲区”或者外设中

2.缓冲区刷新策略的问题

如果有一块数据,一次性写入到外设(效率最高)vs 多次少批量写入外设

缓冲区一定会结合具体的设备,定制自己的刷新策略:

a. 立即刷新——无缓冲

b. 行刷新——行缓存——显示器

c. 缓冲区满再刷新——全缓冲——磁盘文件 (效率最高)

两种特殊情况:

1.用户强制刷新

2.进程退出—— 一般都要进行缓冲区刷新

3.缓冲区的位置

image-20250531172709645

从上面的问题的图片可以看到,缓冲区一定不在内核中,因为如果在内核中,write也应该打印两次,所以我们之前谈论的所有缓冲区,都指的是用户级语言层面给我们提供的缓冲区

这个缓冲区在stdout、stdin、stderr的类型FILE*这个结构体中(不仅包含fd,还包括一个缓冲区),所以我们要自己强制刷新时的fflush(文件指针),以及关闭文件时的fclose(文件指针)都要传一个文件指针,都是因为这些文件指针内包含了内部的缓冲区

关于FILE

image-20250530184801162

image-20250507165056213

所以此时我们可以解决一开始的fork()之后重定向三个c语言接口重复打印两次的问题:

代码结束之前,进行创建子进程

  1. 如果我们没有进行>,就只会看到4条打印的信息 ,是因为stdout默认使用的是行刷新,在进程fork之前,三条C函数已经将数据进行打印输出到显示器上(外设),你的FILE内部,进程内部不存在对应的数据啦

  2. 如果我们进行了>, 写入文件不再是显示器,而是普通文件,采用的刷新策略是全缓冲,之前的3条c显示函数,虽然带了\n,但是不足以让stdout缓冲区写满,数据并没有被刷新!!! 当我们执行fork的时候,stdout属于父进程,创建子进程时, 紧接着就是进程退出! 谁先退出,就一定要进行缓冲区刷新(就是修改) ,发生了写时拷贝!!!数据最终会显示两份

  3. write为什么没有呢?上面的过程都和wirte无关,wirte没有FILE,而用的是fd,就没有C提供的缓冲区

缓冲区和操作系统的关系,我们在C语言封装的接口中要拷贝到缓冲区一次,到os中也要拷贝一次到内核缓冲区中,并且操作系统的刷新策略更复杂

image-20250508170308290

os完全自主决定刷新数据出缓冲区的时机,如果os宕机了,数据要是还没更新出去就会导致数据丢失,如果是在银行这种对数据丢失0容忍的地方肯定是不行的

所以我们可以在用户层告知操作系统强制将对应的该文件的内核缓冲区的数据更新到磁盘上

image-20250508171227521

image-20250508171807739

c++的文件IO流也是一样的,是一个类,其中也要包含缓冲区和文件描述符(fd)

尾声

  本篇发布时正好是端午节,那就祝大家端午节快乐!\^o^/


http://www.hkcw.cn/article/KnIabOIWet.shtml

相关文章

单板机8088C语言计划

计划将原来用汇编写的小程序&#xff0c;用C语言重新写一遍 计划2个月能完成 然后再试试&#xff0c;能不能用C写一下固件BootLoad 和一个类似Dos时代的Debug调试器

C++11 语法特性一文详解

文章目录 1. C11 的发展史2. 列表初始化2.1 C98 中使用 {} 的初始化2.2 C11 中使用 {} 进行初始化2.3 std::initializer_list &#xff08;初始化列表&#xff09; 3. 右值引用与移动语义3.1 左值与右值3.1.1 右值分类 3.2 左值引用与右值引用3.2.1 const 左值引用为什么可以绑…

linux基础

参考视频 文章目录 1.网络的三种链接方式2. 目录结构详解3. 远程登陆和远程文件传输4. vi和vim4.1 vi和vim的三种模式4.2 vim快捷键 5. 关机重启和登录注销5.1 关机重启5.2 登录注销 6. 用户管理6.1 添加和删除用户6.2 用户信息6.3 用户组 7. 实用指令7.1 运行级别7.2 找回root…

【MLLM】多模态LLM 2025上半年技术发展(Better、Faster、Stronger)

note 文章目录 note一、新模型趋势任意模态模型推理模型小巧但功能强大的模型专家混合解码器视觉-语言-行动模型 VLA 二、特殊能力视觉语言模型中的目标检测、分割和计数多模态安全模型多模态RAG&#xff1a;检索器和重排器 三、多模态代理四、视频语言模型五、视觉语言模型的新…

python从零开始实现四极场离子轨迹仿真——框架

本篇将主要讲解程序的框架部分。 该程序主要分为三个部分&#xff0c;首先是初始化部分&#xff0c;主要为设置离子质荷比、初始位置、速度。 其次为求解轨迹部分&#xff0c;通过离子位置获取对应位置的电场&#xff0c;并经由空间电荷效应修改电场后&#xff0c;通过数值求解…

YOLO系列中的C3模块解析2025.5.31

YOLO系列中的 C3模块 是YOLOv5引入的核心组件之一&#xff0c;其设计目标是通过轻量化结构和高效特征提取提升模型性能。以下是C3模块的详细解析&#xff1a; 一、C3模块的网络层级结构 C3模块&#xff08;Cross Stage Partial Network with 3 convolutions&#xff09;结合了…

在Cesium中通过geojson和3d tiles分别加载楼宇白膜

一、geojson渲染楼宇白膜&#xff08;不推荐&#xff09; 如果你没有3dtiles文件来加载白膜&#xff0c;只有geojson加载白膜可以通过GeoJsonDataSource来加载白膜&#xff0c;json格式如下。 实现代码如下 <template><div id"cesium_container"></…

CRISPR-Cas系统的小型化研究进展-文献精读137

Progress in the miniaturization of CRISPR-Cas systems CRISPR-Cas系统的小型化研究进展 摘要 CRISPR-Cas基因编辑技术由于其简便性和高效性&#xff0c;已被广泛应用于生物学、医学、农学等领域的基础与应用研究。目前广泛使用的Cas核酸酶均具有较大的分子量&#xff08;通…

【Web API系列】WebTransportSendStream接口深度解析:构建高性能实时数据传输的基石

前言 随着Web应用复杂度的不断提升&#xff0c;传统的HTTP协议在某些场景下&#xff08;如实时游戏、视频流传输&#xff09;逐渐暴露出性能瓶颈。为解决这一问题&#xff0c;W3C提出了WebTransport API&#xff0c;旨在通过基于QUIC协议的低延迟、多路复用传输机制优化实时通…

MySQL中COUNT(*)、COUNT(1)和COUNT(字段名)的深度剖析与实战应用

MySQL中COUNT语句 三种COUNT函数的解析COUNT(*)COUNT(1)COUNT(字段名) 详细性能比较与实测分析性能差异的理论基础实际性能测试案例 实际案例解析案例1&#xff1a;电商平台订单统计案例2&#xff1a;带条件的计数比较案例3&#xff1a;性能优化实例 COUNT函数与索引的关系详解…

VS Code / Cursor 将默认终端设置为 CMD 完整指南

文章目录 &#x1f9ed; 适用范围&#x1f4cc; 背景与问题分析&#x1f6e0; 配置步骤1. 打开设置&#xff08;settings.json&#xff09;2. 添加或更新配置3. 重启终端与编辑器 &#x1f4a1; 补充&#xff1a;支持多个终端配置&#x1f9ef; 常见问题排查✅ 总结 在 Windows…

数据库高可用架构设计:集群、负载均衡与故障转移实践

关键词:数据库高可用,HA架构,数据库集群,负载均衡,故障转移,SQL Server Always On,MySQL InnoDB Cluster,高可用性组,读写分离,灾难恢复 在当今瞬息万变的数字化时代,数据的价值日益凸显,数据库作为承载核心业务数据的基石,其可用性直接决定了业务的连续性与用户…

【C#】一个简单的http服务器项目开发过程详解

这跟安装NoteJs程序运行脚本文件搭建一个简单Http服务器一样&#xff0c;相比起来&#xff0c;它的优点是可以开发的应用是免安装&#xff0c;跨平台的&#xff0c;放在移动盘上便捷的&#xff0c;这里着重讲http服务器实现的过程&#xff0c;以便自主实现特定的功能和服务。 …

谷歌:贝叶斯框架优化LLM推理反思

&#x1f4d6;标题&#xff1a;Beyond Markovian: Reflective Exploration via Bayes-Adaptive RL for LLM Reasoning &#x1f310;来源&#xff1a;arXiv, 2505.20561 &#x1f31f;摘要 通过强化学习 (RL) 训练的大型语言模型 (LLM) 表现出强大的推理能力和紧急反射行为&a…

C# 文件 I/O 操作详解:从基础到高级应用

在软件开发中&#xff0c;文件操作&#xff08;I/O&#xff09;是一项基本且重要的功能。无论是读取配置文件、存储用户数据&#xff0c;还是处理日志文件&#xff0c;C# 都提供了丰富的 API 来高效地进行文件读写操作。本文将全面介绍 C# 中的文件 I/O 操作&#xff0c;涵盖基…

PCB设计教程【强化篇】——USB拓展坞原理图设计

前言 本教程基于B站Expert电子实验室的PCB设计教学的整理&#xff0c;为个人学习记录&#xff0c;旨在帮助PCB设计新手入门。所有内容仅作学习交流使用&#xff0c;无任何商业目的。若涉及侵权&#xff0c;请随时联系&#xff0c;将会立即处理 目录 前言 一、新建工程与元件…

开源版 PyMOL 如何绘制 Galidesivir 分子结构 ?

参阅&#xff1a;开源版PyMol安装保姆级教程 百度网盘下载 提取码&#xff1a;csub pip show pymol 简介: PyMOL是一个Python增强的分子图形工具。它擅长蛋白质、小分子、密度、表面和轨迹的3D可视化。它还包括分子编辑、射线追踪和动画。 先从 www.python.org 下载 python-…

Leetcode 2819. 购买巧克力后的最小相对损失

1.题目基本信息 1.1.题目描述 现给定一个整数数组 prices&#xff0c;表示巧克力的价格&#xff1b;以及一个二维整数数组 queries&#xff0c;其中 queries[i] [ki, mi]。 Alice 和 Bob 去买巧克力&#xff0c;Alice 提出了一种付款方式&#xff0c;而 Bob 同意了。 对于…

Torch Geometric环境下无线通信网络拓扑推理节点数据缺失实验

节点数据缺失样本生成&#xff1a; gcn_dataset_incomplete.py #作者&#xff1a;zhouzhichao #创建时间&#xff1a;2025/5/30 #内容&#xff1a;生成残缺数据集用于实验import h5py import numpy as np import torch from torch_geometric.data import InMemoryDataset, Da…

【网络与信息安全】实验三 RSA加解密与签名验证

实验三、RSA加解密与签名验证 一、实验基本信息 实验名称&#xff1a;RSA加解密与签名验证实验目的&#xff1a; 理解 RSA 加密解密 与 数字签名验证 的原理。借助 CyberChef 可视化平台&#xff0c;观察和理解加密与签名背后的数据变化。 二、实验环境 操作系统&#xff1a…