【Linux】文件操作、系统IO相关操作、inode和输入输出重定向

news2025/6/2 11:21:23
头像
⭐️个人主页:@小羊
⭐️所属专栏:Linux
很荣幸您能阅读我的文章,诚请评论指点,欢迎欢迎 ~

动图描述

目录

  • 1、理解文件
    • 1.1 狭义理解
    • 1.2 广义理解
    • 1.3 文件操作
    • 1.4 系统角度
  • 2、系统文件IO
    • 2.1 文件相关操作
    • 2.2 文件描述符
    • 2.3 重定向
  • 3、动静态库


1、理解文件

1.1 狭义理解

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

1.2 广义理解

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

1.3 文件操作

  • 对于OKB的空文件是占用磁盘空间的
  • 文件 = 文件属性 + 文件内容
  • 所有的文件操作本质是文件内容操作和文件属性操作

1.4 系统角度

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

2、系统文件IO

2.1 文件相关操作

C语言中文件操作,在操作一个文件之前我们首先要打开它,那么在学了一段时间操作系统后,你知道在操作一个文件之前为什么要先打开吗?
文件存储在磁盘上,CPU执行进程访问文件,而CPU不能直接访问磁盘,所以对于存储在磁盘上的文件如果要被进程访问,首先应该加载到内存中,所以打开文件的过程就是将文件从磁盘加载到内存。

以“w”方式打开文件,这个文件首先被清空然后再写入,也就是如果我们只打开文件但不写入就直接关闭,这个文件就会被清空。
前面我们学习过输出重定向操作符“>”,> file:也是先打开文件然后才操作,如果文件不存在则创建,如果文件存在则清空。

在学习C语言文件操作的时候我们就知道,任何一个程序在启动的时候默认要打开三个文件流stdinstdoutstderr,C++中也有cincoutcerr,其他语言也会支持类似的特性,那么是谁打开呢?通过前面的学习不难推测出是进程默认会打开三个输入输出流。

下面是几种往显示器上输出的方式:

在这里插入图片描述

我们所用的C文件接口,底层一定是封装对应的文件类系统调用,C库函数有:fopenfclosefwritefread,对应系统调用接口有:openclosewriteread。其中fopen底层封装的是系统调用接口openfclose封装的是close等。

在这里插入图片描述

通过一个参数可以传递多个信息:

#include <stdio.h>

#define ONE (1<<0)
#define TWO (1<<1)
#define THREE (1<<2)
#define FOUR (1<<3)
#define FIVE (1<<4)

void test(int flags)
{
	if (flags & ONE)
	{
		printf("one\n");
	}
    if (flags & TWO)
	{
		printf("two\n");
	}
	if (flags & THREE)
	{
		printf("three\n");
	}
	if (flags & FOUR)
	{
		printf("four\n");
	}
	if (flags & FIVE)
	{
		printf("five\n");
	}
}

int main()
{
	test(ONE);
	printf("\n");
	test(ONE | TWO);
	printf("\n");
	test(ONE | TWO | THREE);
	printf("\n");
	test(ONE | TWO | THREE | FOUR);
	printf("\n");
	test(ONE | TWO | THREE | FOUR | FIVE);
	printf("\n");
	return 0;
}

在这里插入图片描述

open选项:
在这里插入图片描述
在这里插入图片描述

简单touch命令:

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

int main(int argc, char *argv[])
{
	open(argv[1], O_CREAT | O_WRONLY, 0666);
    return 0;
}

在这里插入图片描述


2.2 文件描述符

open返回值(文件描述符):
在这里插入图片描述

在这里插入图片描述
从上面的测试中可以看到,默认打开几个文件,文件描述符为什么从3开始呢?
其中的原因文章开头就已经提到过,因为一个程序在启动前默认会打开三个文件流stdinstdoutstderr,怎么证明这件事呢?

yjz@hcss-ecs-8f13:~/linux/text_4.11.15$ ./filecode
hello world
hello world
Are you ok?
yjz@hcss-ecs-8f13:~/linux/text_4.11.15$ cat filecode.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>

int main()
{
	char buffer[100];
	ssize_t s = read(0, buffer, sizeof(buffer));
	if (s > 0) //实际读到的字节大小
	{
		buffer[s - 1] = 0;
		printf("%s\n", buffer);
	}

	const char *str = "Are you ok?\n";
	ssize_t w = write(1, str, strlen(str)); 
	return 0;
}

可以看出stdin文件流的文件描述符是0, stdout文件流的文件描述符是1。

在这里插入图片描述
通过上面的草图,所以fd(文件描述符)究竟是什么呢?其实fd就是数组下标,我们通过这个下标来管理文件,在系统层面,fd是访问文件的唯一方式。

yjz@hcss-ecs-8f13:~/linux/text_4.11.15$ make
gcc -o filecode filecode.c
yjz@hcss-ecs-8f13:~/linux/text_4.11.15$ ./filecode
stdin : 0
stdout : 1
stderr : 2
pf : 3
yjz@hcss-ecs-8f13:~/linux/text_4.11.15$ cat filecode.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>

int main()
{
	printf("stdin : %d\n", stdin->_fileno);
	printf("stdout : %d\n", stdout->_fileno);
	printf("stderr : %d\n", stderr->_fileno);

	FILE *pf = fopen("log.txt", "w");
	printf("pf : %d\n", pf->_fileno);
	
	return 0;
}

FILE是C语言封装的一个文件流类型的结构体。

系统调用接口writeread已经能实现往显示器文件中读和写,为什么语言(以C语言为例)还要做封装呢?
如果我们想在显示器上打印整型1234,而显示器只认字符,所以我们就需要先把1234转换为4个字符,在通过write写到显示器上,这样很麻烦,所以通过对write封装,得到一个printf函数,我们想打印任何类型都可以通过指定打印类型就可以完成打印,底层的复杂转换就不需要我们自己动手了。
在这里插入图片描述

进程打开文件,需要给文件分配新的fd,fd的分配规则是分配最小的、没有被使用的fd。

int main()
{
   	close(1);
	int fd1 = open("log1.txt", O_CREAT | O_WRONLY | O_APPEND, 0666);
	int fd2 = open("log2.txt", O_CREAT | O_WRONLY | O_APPEND, 0666);
	int fd3 = open("log3.txt", O_CREAT | O_WRONLY | O_APPEND, 0666);
	int fd4 = open("log4.txt", O_CREAT | O_WRONLY | O_APPEND, 0666);

	printf("fd1 : %d\n", fd1);
	printf("fd2 : %d\n", fd2);
	printf("fd3 : %d\n", fd3);
	printf("fd4 : %d\n", fd4);

	fflush(stdout);

	close(fd1);
	close(fd2);
	close(fd3);
	close(fd4);
	
	return 0;
}

在这里插入图片描述


2.3 重定向

printf函数只认文件描述符fd,默认向显示器文件(fd为1)中写入,如果我们手动关闭显示器文件,再打开其他文件,则空的fd为1的这个位置就会分配给别的文件,所以printf就会写入到这个文件中。
向上面这种改变file_struct中文件指针的过程就是重定向的过程。

在这里插入图片描述

这是因为./mypipe默认是向stdout中写入,所以./mypipe > test.txt只是改为向test.txt中写入,而stderr本身也是标准文件流,不会被重定向到test.txt中。
那么这里就会有一个疑问,为什么C/C++标准输入是一个,而标准输出有两个呢?(stdout/stderrcout/cerr

在这里插入图片描述
注意:这里的2和>之间不可以有空格,2>在一起的时候才表示错误输出。

输出时可以将正确和错误的信息分离,方便我们做调式。

系统调用接口dup2可以实现输出重定向:
在这里插入图片描述

int main()
{
    int fd = open("log.txt", O_CREAT | O_WRONLY | O_TRUNC, 0666);

	dup2(fd, 1);

	printf("printf fd : %d\n", fd);
	fprintf(stdout, "fprintf fd : %d\n", fd);
	fputs("fputs fd\n", stdout);
	const char *str = "fwrite fd\n";
	fwrite(str, 1, strlen(str), stdout);

	return 0;
}

在这里插入图片描述

对于stdout来说它管只找fd为1的文件,本来fd为1的文件是显示器,通过dup2系统调用将fd为1的位置分配给文件log.txt,最终我们向stdout中输出就输出到了文件log.txt中。

dup2可以实现输入重定向:

int main()
{
    int fd = open("log.txt", O_RDONLY);
	
	dup2(fd, 0);

	char buffer[1024];
	size_t r = read(0, buffer, sizeof(buffer));
	if (r > 0)
	{
		buffer[r] = 0;
		printf("stdin redir: \n%s\n", buffer);
	}

	return 0;
}

在这里插入图片描述

本来0对应的是键盘,通过dup2重定向后从文件log.txt中读取。


3、动静态库

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

如何给系统指定路径,查找自己的动态库?

  1. 拷贝到系统默认路径下,比如/lib64
  2. 在系统路径,建立软链接
  3. Linux系统中,OS查找动态库有默认路径,也存在一个环境变量LD_LIBRARY_PATH,通过这个路径去找
  4. ldconfig 配置/etc/ld.so.conf.d/, ldconfig更新

在这里插入图片描述

如果同时提供.so .a,gcc/g++默认使用动态库,如果要静态链接,带-static。
如果要强制静态链接,必须提供对应的静态库。
如果只提供静态库,但链接方式是动态链接,gcc/g++只能针对.a局部采用静态链接。

动态库连接原理:
在这里插入图片描述

可执行程序、库、.o文件都有特定的格式ELF。

在这里插入图片描述

链接就是将我们的一个个具有相同属性的section进行合并。

对于任何一个文件,文件的内容就是一个巨大的“一维数组”,标识文件任意一个区域,都可以用偏移量+大小的方式。

编辑器编译的时候,就已经形成虚拟地址了。

在这里插入图片描述

程序执行的时候,使用的是虚拟地址。
虚拟地址空间是OS、CPU、编译器共同协作的产物。

为什么要有虚拟地址和虚拟地址空间?
除了保护物理内存,做权限检查,让进程以统一的视角看物理内存,还有是编译器在编译代码的时候不用考虑物理内存的情况,统一使用虚拟地址,以线性的方式看待整个代码和数据,实现操作系统和编译器的解耦。


本篇文章的分享就到这里了,如果您觉得在本文有所收获,还请留下您的三连支持哦~

头像

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Jetson Xavier NX (ARM) 使用 PyTorch 安装 Open3D-ML 指南

由于 Jetson 为 ARM64 (aarch64) 的系统架构&#xff0c;所以不能用 pip install 直接安装&#xff0c;需要通过源码编译。 升级系统 JetPack 由于 Open3D-ML 目前只支持 CUDA 10.0 以及 CUDA 11.*&#xff0c;并且 JetPack 的 CUDA 开发环境只有10.2、11.4以及12.2&#xff0…

【Vim Masterclass 笔记25】S10L45:Vim 多窗口的常用操作方法及相关注意事项

文章目录 S10L45 Working with Multiple Windows1 水平分割窗口2 在水平分割的新窗口中显示其它文件内容3 垂直分割窗口4 窗口的关闭5 在同一窗口水平拆分出多个窗口6 关闭其余窗口7 让四个文件呈田字形排列8 光标在多窗口中的定位9 调节子窗口的尺寸大小10 变换子窗口的位置11…

《keras 3 内卷神经网络》

keras 3 内卷神经网络 作者&#xff1a;Aritra Roy Gosthipaty 创建日期&#xff1a;2021/07/25 最后修改时间&#xff1a;2021/07/25 描述&#xff1a;深入研究特定于位置和通道无关的“内卷”内核。 &#xff08;i&#xff09; 此示例使用 Keras 3 在 Colab 中查看 GitHub …

Linux 进程环境变量:深入理解与实践指南

&#x1f31f; 快来参与讨论&#x1f4ac;&#xff0c;点赞&#x1f44d;、收藏⭐、分享&#x1f4e4;&#xff0c;共创活力社区。&#x1f31f; &#x1f6a9;用通俗易懂且不失专业性的文字&#xff0c;讲解计算机领域那些看似枯燥的知识点&#x1f6a9; 在 Linux 系统里…

【博客之星】2024年度总结

&#x1f468;‍&#x1f393;博主简介 &#x1f3c5;CSDN博客专家   &#x1f3c5;云计算领域优质创作者   &#x1f3c5;华为云开发者社区专家博主   &#x1f3c5;阿里云开发者社区专家博主 &#x1f48a;交流社区&#xff1a;运维交流社区 欢迎大家的加入&#xff01…

Linux下php8安装phpredis扩展的方法

Linux下php8安装phpredis扩展的方法 下载redis扩展执行安装编辑php.ini文件重启php-fpmphpinfo 查看 下载redis扩展 前提是已经安装好redis服务了 php-redis下载地址 https://github.com/phpredis/phpredis 执行命令 git clone https://github.com/phpredis/phpredis.git执行…

训练大模型所需要的内存计算

计算训练一个7B参数大模型所需的显存&#xff0c;主要涉及以下几个方面&#xff1a; 1. 模型参数 每个参数通常需要4字节&#xff08;32位浮点数&#xff09;&#xff0c;因此7B参数的显存需求为&#xff1a; 2. 优化器状态 常见的优化器如Adam&#xff0c;每个参数需要存…

笋瓜果实的代谢组学和转录组分析-文献精读103

Metabolomics and Transcription Profiling of Pumpkin Fruit Reveals Enhanced Bioactive Flavonoids and Coumarins in Giant Pumpkin (Cucurbita maxima) 笋瓜果实的代谢组学和转录组分析揭示了笋瓜&#xff08;Cucurbita maxima&#xff09;中生物活性黄酮和香豆素的增强 …

Jenkins下载 Maven、Allure 插件并且配置环境

文章目录 Jenkins在插件中心下载 maven、allure插件maven插件下载allure插件下载 配置maven、allure 往期推荐&#xff1a; 最新! 在 Linux上搭建Jenkins环境! Jenkins邮件通知的详细配置含邮件通知模板&#xff01; Jenkin配置企业微信通知 Jenkins在插件中心下载 maven、…

【深度学习】微积分

微积分 在2500年前&#xff0c;古希腊人把一个多边形分成三角形&#xff0c;并把它们的面积相加&#xff0c;才找到计算多边形面积的方法。 为了求出曲线形状&#xff08;比如圆&#xff09;的面积&#xff0c;古希腊人在这样的形状上刻内接多边形。 如图2.4.1所示&#xff0c…

宝塔Linux+docker部署nginx出现403 Forbidden

本文主要讲述了宝塔docker部署nginx出现403 Forbidden的原因&#xff0c;以及成功部署前端的方法步骤。 目录 1、问题描述2、问题检测2.1 检测监听端口是否异常2.2 检测Docker容器是否异常2.2.1 打开宝塔Linux的软件商店&#xff0c;找到Docker管理器&#xff0c;查看前端容器是…

Tensor 基本操作2 理解 tensor.max 操作,沿着给定的 dim 是什么意思 | PyTorch 深度学习实战

前一篇文章&#xff0c;Tensor 基本操作1 | PyTorch 深度学习实战 本系列文章 GitHub Repo: https://github.com/hailiang-wang/pytorch-get-started 目录 Tensor 基本操作torch.max默认指定维度 Tensor 基本操作 torch.max torch.max 实现降维运算&#xff0c;基于指定的 d…

[Linux] 进程管理与调度机制

文章目录 一.进程前言1.冯诺依曼体系结构2.操作系统 二.进程相关概念1.PCB2.查看进程标识符3.父与子进程 三.进程状态1.状态类别1).运行2).阻塞3).挂起 2.Linux下的状态1).R(running)2).S(Sleeping)3).D(disk sleeping)4).T(stopped)5).t(tracing stopped)6).Z(僵尸进程)7).孤儿…

复位信号的同步与释放(同步复位、异步复位、异步复位同步释放)

文章目录 背景前言一、复位信号的同步与释放1.1 同步复位1.1.1 综述1.1.2 优缺点 1.2 recovery time和removal time1.3 异步复位1.3.1 综述1.3.2 优缺点 1.4 同步复位 与 异步复位1.5 异步复位、同步释放1.5.1 总述1.5.2 机理1.5.3 复位网络 二、思考与补充2.1 复…

Unity中关于实现 管道水流+瀑布流动+大肠蠕动效果笔记

Unity中关于实现 管道水流瀑布流动大肠蠕动效果笔记 效果展示&#xff1a; 参考资料及链接&#xff1a; 1、如何在 Unity 中创建水效果 - 水弯曲教程 https://www.youtube.com/watch?v3CcWus6d_B8 关于补充个人技能中&#xff1a;顶点噪波影响网格着色器配合粒子实现水特效 …

Cloudpods是一个开源的Golang实现的云原生的融合多云/混合云的云平台,也就是一个“云上之云”。

Cloudpods是一个开源的Golang实现的云原生的融合多云/混合云的云平台&#xff0c;也就是一个“云上之云”。Cloudpods不仅可以管理本地的虚拟机和物理机资源&#xff0c;还可以管理多个云平台和云账号。Cloudpods隐藏了这些异构基础设施资源的数据模型和API的差异&#xff0c;对…

【LeetCode】--- MySQL刷题集合

1.组合两个表&#xff08;外连接&#xff09; select p.firstName,p.lastName,a.city,a.state from Person p left join Address a on p.personId a.personId; 以左边表为基准&#xff0c;去连接右边的表。取两表的交集和左表的全集 2.第二高的薪水 &#xff08;子查询、if…

JavaScript学习笔记(3)

一.BOM对象 BOM的全称是Browser Object Model,翻译过来是浏览器对象模型。也就 是JavaScript将浏览器的各个组成部分封装成了对象。我们要操作浏览器的部分功能&#xff0c;可以通过操作 BOM对象的相关属性或者函数来完成。例如&#xff1a;我们想要将浏览器的地址改为 http:/…

DRG/DIP 2.0时代下基于PostgreSQL的成本管理实践与探索(下)

五、数据处理与 ETL 流程编程实现 5.1 数据抽取与转换(ETL) 在 DRG/DIP 2.0 时代的医院成本管理中,数据抽取与转换(ETL)是将医院各个业务系统中的原始数据转化为可供成本管理分析使用的关键环节。这一过程涉及从医院 HIS 系统中抽取患者诊疗数据,并对其进行格式转换、字…

【玩转全栈】----YOLO8训练自己的模型并应用

继上篇&#xff1a; 【玩转全栈】---基于YOLO8的图片、视频目标检测-CSDN博客 相信大家已经可以训练一些图片和视频了&#xff0c;接下来我将为大家介绍如何训练自己的特定模型&#xff0c;并用其进行检测 目录 准备数据 图片数据 标识数据 配置文件 运行 测试训练结果 存在的问…