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

【Linux】详谈 基础I/O

目录

一、理解文件

狭义的理解:

广义理解:

文件操作的归类认知

系统角度

二、系统文件I/O

2.1 标志位的传递

系统级接口open

​编辑

open返回值

写入文件

读文件

三、文件描述符

3.1(0 & 1 & 2)

3.2 文件描述符的分配规则

3.3 重定向

3.4 dup2系统调用

标准错误


一、理解文件

文件类型:

  • 普通文件:包含用户数据,如文本文件、二进制可执行文件、图像文件、音频文件等。文本文件可以用文本编辑器打开查看和编辑,二进制文件则包含了机器可执行的指令或特定格式的数据。
  • 目录文件:用于组织和管理其他文件和目录,类似于 Windows 系统中的文件夹。它包含了指向其他文件和目录的索引信息。
  • 设备文件:在Linux中,硬件设备也被视为文件,分为字符设备文件和块设备文件。字符设备文件通常用于像串口、终端这样以字符流方式进行数据传输的设备;块设备文件用于如硬盘、U盘等以块为单位进行数据读写的设备。
  • 链接文件:类似于 Windows系统中的快捷方式,分为硬链接和软链接(符号链接)。硬链接是同一个文件的多个名称,它们共享相同的 inode号;软链接则是指向另一个文件的特殊文件,有自己独立的 inode 号。
  • 管道文件:主要用于进程间通信,允许两个或多个进程之间进行数据的传递和共享。
  • 套接字文件:用于网络通信或本地进程间通信,是网络编程和一些进程间通信机制的重要组成部分。

狭义的理解:

• 文件在磁盘里
• 磁盘是永久性存储介质,因此文件在磁盘上的存储是永久性的
• 磁盘是外设(即是输出设备也是输入设备)
• 磁盘上的文件 本质是对文件的所有操作,都是对外设的输入和输出 简称 IO

广义理解:

Linux 下一切皆文件(键盘、显示器、网卡、磁盘…… 这些都是抽象化的过程)

文件操作的归类认知

• 对于 0KB 的空文件是占用磁盘空间的
• 文件是文件属性(元数据)和文件内容的集合(文件 = 属性(元数据)+ 内容)
• 所有的文件操作本质是文件内容操作和文件属性操作

系统角度

• 对文件的操作本质是进程对文件的操作
• 磁盘的管理者是操作系统
• 文件的读写本质不是通过 C 语言 / C++ 的库函数来操作的(这些库函数只是为用户提供方便),而、是通过文件相关的系统调用接口来实现的

二、系统文件I/O

打开文件的方式不仅仅是fopen,ifstream等流式,语言层的方案,其实系统才是打开文件最底层的方案。不过,在学习系统文件IO之前,先要了解下如何给函数传递标志位,该方法在系统文件IO接口中会使用到:

2.1 标志位的传递

系统级接口open

#include <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);
pathname: 要打开或创建的⽬标⽂件
flags: 打开⽂件时,可以传⼊多个参数选项,⽤下⾯的⼀个或者多个常量进⾏“或”运算,构成
flags。
参数:O_RDONLY: 只读打开O_WRONLY: 只写打开O_RDWR : 读,写打开这三个常量,必须指定⼀个且只能指定⼀个O_CREAT : 若⽂件不存在,则创建它。需要使⽤mode选项,来指明新⽂件的访问
权限O_APPEND: 追加写
返回值:成功:新打开的⽂件描述符失败:-1
open返回值

在认识返回值之前,先来认识⼀下两个概念: 系统调⽤ 和 库函数

• 上⾯的 fopen fclose fread fwrite 都是C标准库当中的函数,我们称之为库函数(libc)。
• ⽽ open close read write lseek 都属于系统提供的接⼝,称之为系统调⽤接⼝

系统调⽤接⼝和库函数的关系,⼀⽬了然。
所以,可以认为, f# 系列的函数,都是对系统调⽤的封装,⽅便⼆次开发。

写入文件

清空并写入

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>int main()
{umask(0);int fd=open("log.txt",O_CREAT | O_WRONLY | O_TRUNC,0666);if(fd<0){perror("open");return 1;}printf("fd: %d\n",fd);const char* msg="hello hhh";int cnt=1;while(cnt--){write(fd,msg,strlen(msg));}close(fd);return 0;
}

追加并写入

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>int main()
{umask(0);int fd=open("log.txt",O_CREAT | O_WRONLY | O_TRUNC ,0666);if(fd<0){perror("open");return 1;}printf("fd: %d\n",fd);const char* msg="hello bbbb";int cnt=1;while(cnt--){write(fd,msg,strlen(msg));}close(fd);return 0;
}

注意上面的加入函数umask(0);就可以自己规范权限。

读文件

int main()
{int fd = open("myfile", O_RDONLY);if(fd < 0){perror("open");return 1;} const char *msg = "hello bit!\n";char buf[1024];while(1)
{ssize_t s = read(fd, buf, strlen(msg));//类⽐writeif(s > 0){printf("%s", buf);}else{break;}} close(fd);return 0;
}

这里的接口都是系统调用,而上面的c语言的文件操作都是语言层面上的调用。其实语言层里面的调用里面都封装着系统级别的调用。

三、文件描述符

文件描述符是一个非负整数,它是 Linux 内核为了管理文件操作而给每个打开的文件或其他 I/O 资源(如管道、套接字等)分配的一个标识符。可以将其理解为一个指向内核中代表打开文件的数据结构的索引,通过这个索引,程序能够方便地对相应的文件或资源进行各种读写等操作。

在操作系统层面接口层面,系统只认文件描述符(fd)。所有根据前面所讲,语言层面肯定封装了文件fd。

3.1(0 & 1 & 2)

• Linux进程默认情况下会有3个缺省打开的文件描述符,分别是标准输入0, 标准输出1, 标准错误2.
• 0,1,2对应的物理设备一般是:键盘,显示器,显示器

所以输⼊输出还可以采⽤如下⽅式:

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
int main()
{char buf[1024];ssize_t s = read(0, buf, sizeof(buf));if(s > 0){buf[s] = 0;write(1, buf, strlen(buf));write(2, buf, strlen(buf));}return 0;
}

而现在知道,文件描述符就是从0开始的小整数。当我们打开文件时,操作系统在内存中要创建相应的数据结构来描述目标文件。于是就有了file结构体。表示一个已经打开的文件对象。而进程执行open系统调用,所以必须让进程和文件关联起来。每个进程都有一个指针*files, 指向一张表files_struct,该表最重要的部分就是包含一个指针数组,每个元素都是一个指向打开文件的指针!所以,本质上,文件描述符就是该数组的下标。所以,只要拿着文件描述符,就可以找到对应的文件。

对于以上原理结论我们可通过内核源码验证:
首先要找到task_struct 结构体在内核中为位置,地址为: /usr/src/kernels/3.10.0-1160.71.1.el7.x86_64/include/linux/sched.h (3.10.0-1160.71.1.el7.x86_64是内核版本,可使用 uname -a 自行查看服务器配置, 因为这个文件夹只有一个,所以也不用刻意去分辨,内核版本其实也随意)

3.2 文件描述符的分配规则

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main()
{int fd = open("myfile", O_RDONLY);if(fd < 0){perror("open");return 1;}printf("fd: %d\n", fd);close(fd);return 0;
}

输出发现是fd: 3

关闭0或者2,在看

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main()
{close(0);//close(2);int fd = open("myfile", O_RDONLY);if(fd < 0){perror("open");return 1;}printf("fd: %d\n", fd);close(fd);return 0;
}

发现是结果是: fd: 0 或者 fd 2 ,可⻅,文件描述符的分配规则:在files_struct数组当中,找到当前没有被使⽤的最小的⼀个下标,作为新的文件描述符。

3.3 重定向

那如果关闭1呢?看代码:

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
int main()
{close(1);int fd = open("myfile", O_WRONLY|O_CREAT, 00644);if(fd < 0){perror("open");return 1;}printf("fd: %d\n", fd);fflush(stdout);close(fd);exit(0);
}

此时,我们发现,本来应该输出到显⽰器上的内容,输出到了⽂件 myfile 当中,其中,fd=1。这种现象叫做输出重定向。常见的重定向有: > ,>> ,<

重定向的本质

3.4 dup2系统调用

int main() {// 打开文件,如果文件不存在则创建,同时以读写模式打开int fd = open("./log", O_CREAT | O_RDWR);if (fd < 0) {perror("open");return 1;}// 关闭标准输出文件描述符close(1);// 将文件描述符 fd 复制到标准输出文件描述符(1)dup2(fd, 1);for (;;) {char buf[1024] = {0};// 从标准输入读取数据到缓冲区ssize_t read_size = read(0, buf, sizeof(buf) - 1);if (read_size < 0) {perror("read");break;}// 输出读取到的内容printf("%s", buf);// 刷新标准输出缓冲区fflush(stdout);}return 0;
}

标准错误

向标准输出和标准错误里打信息

标准输出和标准错误都是显示器文件,想把标准输出和标准错误的信息重定向一个文件。这样是不行的。可以发现两者在两个文件中

用下面这个指令进行重定向,重定向到了两个文件

用下面这个指令可以把两者重定向到一个文件

存在一个标准错误,可以通过重定向能力把常规消息和错误消息进行分离。以方便后续用户进行操作好区分。


 本篇完,下篇见!

相关文章:

【Linux】详谈 基础I/O

目录 一、理解文件 狭义的理解&#xff1a; 广义理解&#xff1a; 文件操作的归类认知 系统角度 二、系统文件I/O 2.1 标志位的传递 系统级接口open ​编辑 open返回值 写入文件 读文件 三、文件描述符 3.1&#xff08;0 & 1 & 2&#xff09; 3.2 文件描…...

爬虫案例七Python协程爬取视频

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、Python协程爬取视频 前言 提示&#xff1a;这里可以添加本文要记录的大概内容&#xff1a; 爬虫案例七协程爬取视频 提示&#xff1a;以下是本篇文章正文…...

[20250304] 关于 RISC-V芯片 的介绍

[20250304] 关于 RISC-V芯片 的介绍 1. 调研报告 一、RISC-V 芯片结构分析 RISC-V 芯片基于开源指令集架构&#xff08;ISA&#xff09;&#xff0c;其核心优势在于模块化设计与高度灵活性。 指令集架构 基础指令集&#xff1a;包含 RV32I&#xff08;32 位&#xff09;、R…...

一学就会:A*算法详细介绍(Python)

&#x1f4e2;本篇文章是博主人工智能学习以及算法研究时&#xff0c;用于个人学习、研究或者欣赏使用&#xff0c;并基于博主对相关等领域的一些理解而记录的学习摘录和笔记&#xff0c;若有不当和侵权之处&#xff0c;指出后将会立即改正&#xff0c;还望谅解。文章分类在&am…...

Hadoop、Hive、Spark的关系

Part1&#xff1a;Hadoop、Hive、Spark关系概览 1、MapReduce on Hadoop 和spark都是数据计算框架&#xff0c;一般认为spark的速度比MR快2-3倍。 2、mapreduce是数据计算的过程&#xff0c;map将一个任务分成多个小任务&#xff0c;reduce的部分将结果汇总之后返回。 3、HIv…...

Excel·VBA江西省预算一体化工资表一键处理

每月制作工资表导出为Excel后都需要调整格式&#xff0c;删除0数据的列、对工资表项目进行排序、打印设置等等&#xff0c;有些单位还分有“行政”、“事业”2个工资表就需要操作2次。显然&#xff0c;这种重复操作的问题&#xff0c;可以使用VBA代码解决 目录 代码使用说明1&a…...

23种设计模式简介

一、创建型&#xff08;5种&#xff09; 1.工厂方法 总店定义制作流程&#xff0c;分店各自实现特色披萨&#xff08;北京店-烤鸭披萨&#xff0c;上海店-蟹粉披萨&#xff09; 2.抽象工厂 套餐工厂&#xff08;家庭装含大披萨薯条&#xff0c;情侣装含双拼披萨红酒&#…...

python fire 库与 sys.argv 处理命令行参数

fire库 Python Fire 由Google开发&#xff0c;它使得命令行接口&#xff08;CLI&#xff09;的创建变得容易。使用Python Fire&#xff0c;可以将Python对象&#xff08;如类、函数或字典&#xff09;转换为可以从终端运行的命令行工具。这能够以一种简单而直观的方式与你的Py…...

PDF处理控件Aspose.PDF,如何实现企业级PDF处理

PDF处理为何成为开发者的“隐形雷区”&#xff1f; “手动调整200页PDF目录耗时3天&#xff0c;扫描件文字识别错误导致数据混乱&#xff0c;跨平台渲染格式崩坏引发客户投诉……” 作为开发者&#xff0c;你是否也在为PDF处理的复杂细节消耗大量精力&#xff1f;Aspose.PDF凭…...

Spring(1)——mvc概念,部分常用注解

1、什么是Spring Web MVC&#xff1f; Spring MVC 是一种基于 Java 的实现了 MVC&#xff08;Model-View-Controller&#xff0c;模型 - 视图 - 控制器&#xff09;设计模式的 Web 应用框架&#xff0c;它是 Spring 框架的一个重要组成部分&#xff0c;用于构建 Web 应用程序。…...

C语言(23)

字符串函数 11.strstr函数 1.1函数介绍&#xff1a; 头文件&#xff1a;string.h char *strstr ( const char * str1,const char *str2); 作用&#xff1a;在一个字符串&#xff08;str1&#xff09;中寻找另外一个字符串&#xff08;str2&#xff09;是否出现过 如果找到…...

Immich自托管服务的本地化部署与随时随地安全便捷在线访问数据

文章目录 前言1.关于Immich2.安装Docker3.本地部署Immich4.Immich体验5.安装cpolar内网穿透6.创建远程链接公网地址7.使用固定公网地址远程访问 前言 小伙伴们&#xff0c;你们好呀&#xff01;今天要给大家揭秘一个超炫的技能——如何把自家电脑变成私人云相册&#xff0c;并…...

基于SpringBoot的在线付费问答系统设计与实现(源码+SQL脚本+LW+部署讲解等)

专注于大学生项目实战开发,讲解,毕业答疑辅导&#xff0c;欢迎高校老师/同行前辈交流合作✌。 技术范围&#xff1a;SpringBoot、Vue、SSM、HLMT、小程序、Jsp、PHP、Nodejs、Python、爬虫、数据可视化、安卓app、大数据、物联网、机器学习等设计与开发。 主要内容&#xff1a;…...

【Linux】信号处理以及补充知识

目录 一、信号被处理的时机&#xff1a; 1、理解&#xff1a; 2、内核态与用户态&#xff1a; 1、概念&#xff1a; 2、重谈地址空间&#xff1a; 3、处理时机&#xff1a; 补充知识&#xff1a; 1、sigaction&#xff1a; 2、函数重入&#xff1a; 3、volatile&…...

pandas——to_datatime用法

Pandas中pd.to_datetime的用法及示例 pd.to_datetime 是 Pandas 库中用于将字符串、整数或列表转换为日期时间&#xff08;datetime&#xff09;对象的核心函数。它在处理时间序列数据时至关重要&#xff0c;能够灵活解析多种日期格式并统一为标准时间类型。以下是其核心用法及…...

《DataWorks 深度洞察:量子机器学习重塑深度学习架构,决胜复杂数据战场》

在数字化浪潮汹涌澎湃的当下&#xff0c;大数据已然成为推动各行业发展的核心动力。身处这一时代洪流&#xff0c;企业对数据的处理与分析能力&#xff0c;直接关乎其竞争力的高低。阿里巴巴的DataWorks作为大数据领域的扛鼎之作&#xff0c;凭借强大的数据处理与分析能力&…...

Java 大视界 -- 基于 Java 的大数据实时数据处理框架性能评测与选型建议(121)

&#x1f496;亲爱的朋友们&#xff0c;热烈欢迎来到 青云交的博客&#xff01;能与诸位在此相逢&#xff0c;我倍感荣幸。在这飞速更迭的时代&#xff0c;我们都渴望一方心灵净土&#xff0c;而 我的博客 正是这样温暖的所在。这里为你呈上趣味与实用兼具的知识&#xff0c;也…...

多线程-JUC

简介 juc&#xff0c;java.util.concurrent包的简称&#xff0c;java1.5时引入。juc中提供了一系列的工具&#xff0c;可以更好地支持高并发任务 juc中提供的工具 可重入锁 ReentrantLock 可重入锁&#xff1a;ReentrantLock&#xff0c;可重入是指当一个线程获取到锁之后&…...

DeepSeek:中国AGI先锋,用技术重塑通用人工智能的未来

在ChatGPT掀起全球大模型热潮的背景下&#xff0c;中国AI领域涌现出一批极具创新力的技术公司&#xff0c;深度求索&#xff08;DeepSeek&#xff09;​便是其中的典型代表。这家以“探索未知、拓展智能边界”为使命的AI企业&#xff0c;凭借长文本理解、逻辑推理与多模态技术的…...

Vue 框架深度解析:源码分析与实现原理详解

文章目录 一、Vue 核心架构设计1.1 整体架构流程图1.2 模块职责划分 二、响应式系统源码解析2.1 核心类关系图2.2 核心源码分析2.2.1 数据劫持实现2.2.2 依赖收集过程 三、虚拟DOM与Diff算法实现3.1 Diff算法流程图3.2 核心Diff源码 四、模板编译全流程剖析4.1 编译流程图4.2 编…...

Python爬虫获取淘宝快递费接口的详细指南

在电商运营中&#xff0c;快递费用的透明化和精准计算对于提升用户体验、优化物流成本以及增强市场竞争力至关重要。淘宝提供的 item_fee 接口能够帮助开发者快速获取商品的快递费用信息。本文将详细介绍如何使用 Python 爬虫技术结合 item_fee 接口&#xff0c;实现高效的数据…...

基于BMO磁性细菌优化的WSN网络最优节点部署算法matlab仿真

目录 1.程序功能描述 2.测试软件版本以及运行结果展示 3.核心程序 4.本算法原理 5.完整程序 1.程序功能描述 无线传感器网络&#xff08;Wireless Sensor Network, WSN&#xff09;由大量分布式传感器节点组成&#xff0c;用于监测物理或环境状况。节点部署是 WSN 的关键问…...

Android Activity的启动器ActivityStarter入口

Activity启动器入口 Android的Activity的启动入口是在ActivityStarter类的execute()&#xff0c;在该方法里面继续调用executeRequest(Request request) &#xff0c;相应的参数都设置在方法参数request中。代码挺长&#xff0c;分段现在看下它的实现&#xff0c;分段一&#x…...

Python深度学习算法介绍

一、引言 深度学习是机器学习的一个重要分支&#xff0c;它通过构建多层神经网络结构&#xff0c;自动从数据中学习特征表示&#xff0c;从而实现对复杂模式的识别和预测。Python作为一门强大的编程语言&#xff0c;凭借其简洁易读的语法和丰富的库支持&#xff0c;成为深度学…...

关于sqlalchemy的使用

关于sqlalchemy的使用 说明一、sqlachemy总体使用思路二、安装与创建库、连结库三、创建表、增加数据四、查询记录五、更新或删除六、关联表定义七、一对多关联查询八、映射类定义与添加记录 说明 本教程所需软件及库python3.10、sqlalchemy安装与创建库、连结库创建表、增加数…...

利用LLMs准确预测旋转机械(如轴承)的剩余使用寿命(RUL)

研究背景 研究问题:如何准确预测旋转机械(如轴承)的剩余使用寿命(RUL),这对于设备可靠性和减少工业系统中的意外故障至关重要。研究难点:该问题的研究难点包括:训练和测试阶段数据分布不一致、长期RUL预测的泛化能力有限。相关工作:现有工作主要包括基于模型的方法、数…...

深度学习 PyTorch 中 18 种数据增强策略与实现

深度学习pytorch之简单方法自定义9类卷积即插即用 数据增强通过对训练数据进行多种变换&#xff0c;增加数据的多样性&#xff0c;它帮助我们提高模型的鲁棒性&#xff0c;并减少过拟合的风险。PyTorch 提供torchvision.transforms 模块丰富的数据增强操作&#xff0c;我们可以…...

视觉图像处理

在MATLAB中进行视觉图像处理仿真通常涉及图像增强、滤波、分割、特征提取等操作。以下是一个分步指南和示例代码,帮助您快速入门: 1. MATLAB图像处理基础步骤 1.1 读取和显示图像 % 读取图像(替换为实际文件路径) img = imread(lena.jpg); % 显示原图 figure; subplot(2…...

深度学习与普通神经网络有何区别?

深度学习与普通神经网络的主要区别体现在以下几个方面&#xff1a; 一、结构复杂度 普通神经网络&#xff1a;通常指浅层结构&#xff0c;层数较少&#xff0c;一般为2-3层&#xff0c;包括输入层、一个或多个隐藏层、输出层。深度学习&#xff1a;强调通过5层以上的深度架构…...

Vue3、vue学习笔记

<!-- Vue3 --> 1、Vue项目搭建 npm init vuelatest cd 文件目录 npm i npm run dev // npm run _ 这个在package.json中查看scripts /* vue_study\.vscode可删 // vue_study\src\components也可删除(基本语法&#xff0c;不使用组件) */ // vue_study\.vscode\lau…...