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

头像
⭐️个人主页:@小羊
⭐️所属专栏: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.mzph.cn/bicheng/68946.shtml

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

相关文章

头像生成小程序搭建(免费分享)

如下图为小程序页面的基本效果&#xff0c;下面将介绍该小程序的功能 页面template代码如下&#xff1a; <template><view class"avatar-containner"><block v-if"!showCropper"><image class"pageback" src"../../s…

2025寒假备战蓝桥杯02---朴素二分查找升级版本的学习+分别求解左右端点

文章目录 1.朴素二分查找的升级版2.查找左端点3.查找右端点4.代码的编写 1.朴素二分查找的升级版 和之前介绍的这个二分查找相比&#xff0c;我觉得这个区别就是我们的这个二分查找需要找到的是一个区间&#xff0c;而不是这个区间里面的某一个元素的位置&#xff1b; 2.查找…

css命名规范——BEM

目录 引言 BEM是什么? 块Block 元素Element 修饰语Modifier BEM解决了哪些问题? 在流行框架的组件中使用 BEM 格式 实战 认识设计图 如何使用当前的css规范正确命名? 引言 css样式类命名难、太难了,难于上青天,这个和js变量命名还不一样。看看项目中五花八门的样…

C++AVL树(一)详解

文章目录 AVL树概念AVL树的插入平衡因子的更新旋转的规则左单旋右单旋抽象的情况h0h1h 2h 3 AVL树 概念 AVL树是一棵平衡二叉查找树&#xff0c;AVL树是空树&#xff0c;保证左右子树都是AVL树&#xff0c;AVL树要求高度差的绝对值不超过1&#xff0c;因为最好情况是1&#…

JAVA与数据结构-线性表

目录 一.线性表的概念 二.线性表的关系及分类 三.数组与顺序表 四.链表 1.静态链表(链表的的数组底层实现&#xff09; 2.循环链表 3.双向链表 五.栈 1.栈的概念 2.栈的底层实现 3.共享空间栈 4.逆波兰表达式&#xff08;后缀表达式&#xff09; 5.栈与递归 六.…

AI绘画:从灵感到杰作的奇幻之旅(3/10)

AI 绘画&#xff1a;新时代的艺术创作浪潮 在数字化时代的浪潮下&#xff0c;AI 绘画已成为艺术领域中一颗耀眼的新星&#xff0c;掀起了一场前所未有的创作革命。只需在相关工具中输入简单的文字描述&#xff0c;或者上传一张参考图片&#xff0c;就能迅速生成令人惊叹的艺术…

【C语言系列】深入理解指针(3)

深入理解指针&#xff08;3&#xff09; 一、字符指针变量二、数组指针变量2.1数组指针变量是什么&#xff1f;2.2数组指针变量怎么初始化&#xff1f; 三、二维数组传参的本质四、函数指针变量4.1函数指针变量的创建4.2函数指针变量的使用4.3两段有趣的代码4.4 typedef关键字 …

广东某海水取排水管线工程边坡自动化监测

1. 项目简介 广东廉江核电项目田螺岭厂址位于廉江市车板镇北约4km处&#xff0c;地理位置为东经10948’28.88“北纬2134’01.55”&#xff0c;东距廉江市约48km&#xff0c;东南距湛江市约 65km&#xff0c;厂址西南距离北部湾约4.5km。广东廉江核电项目一期工程海水取排水管线…

Qt基础项目篇——Qt版Word字处理软件

一、核心功能 本软件为多文档型程序&#xff0c;界面是标准的 Windows 主从窗口 拥有&#xff1a;主菜单、工具栏、文档显示区 和 状态栏。 所要实现的东西&#xff0c;均在下图了。 开发该软件&#xff0c;主要分为下面三个阶段 1&#xff09;界面设计开发 多窗口 MDI 程序…

神经网络梯度爆炸的原因及解决方案

在深度学习中&#xff0c;梯度爆炸&#xff08;gradient exploding&#xff09;是一种常见的训练问题&#xff0c;尤其是在深层神经网络中。梯度爆炸指的是在反向传播过程中&#xff0c;梯度值呈指数级增长&#xff0c;导致网络权重的大幅更新&#xff0c;从而使得网络变得不稳…

deap系统重构,再新增一个新的因子,年化39.1%,卡玛提升至2.76(附python代码)

原创内容第776篇&#xff0c;专注量化投资、个人成长与财富自由。 本周核心工作之一&#xff0c;deap因子挖掘&#xff1a; Deap牛刀小试&#xff0c;挖掘出长期年化29.2%的轮动因子 deap时间序列函数补充&#xff0c;挖掘出年化39.12%的轮动因子&#xff0c;卡玛比率2.52 …

计算机图形学:实验二 三维模型读取与控制

一、程序功能设计 通过键盘和鼠标结合实现了对三维牛模型的变换控制&#xff0c;可以灵活调整旋转的轴、方向、速度以及暂停或复位三维牛模型状态。 动画启动和暂停&#xff1a; 按键&#xff1a;鼠标左键&#xff08;启动&#xff09;&#xff0c;鼠标右键&#xff08;暂停…

最新-CentOS 7 基于1 Panel面板安装 JumpServer 堡垒机

CentOS 7 基于1 Panel面板安装 JumpServer 堡垒机 一、前言二、设备要求三、环境要求四、安装4.1 环境安装4.2 JumpServer安装4.3 访问JumpServerWeb端&#xff0c;进行登录 五、登录Web控制台 一、前言 JumpServer是广受欢迎的开源堡垒机。运维必备神器&#xff01;JumpServe…

WordPress果果对象存储插件

将网站上的图片等静态资源文件上传至七牛云对象存储&#xff0c;可以减轻服务器文件存储压力&#xff0c;提升静态文件访问速度&#xff0c;从而加速网站访问速度。 支持&#xff1a;阿里云对象存储、华为云对象存储、百度云对象存储、腾讯云对象存储、七牛云对象存储。 下载…

ChatGPT大模型极简应用开发-CH2-深入了解 GPT-4 和 ChatGPT 的 API

文章目录 2.1 基本概念2.2 OpenAI API 提供的可用模型2.3 在 OpenAI Playground 中使用 GPT模型2.4 开始使用 OpenAI Python 库2.4.1 OpenAI 访问权限和 API 密钥2.4.2 Hello World 示例程序 2.5 使用 GPT-4 和 ChatGPT2.5.1 ChatCompletion 端点的输入选项2.5.2 ChatCompletio…

war包 | Docker部署flowable-ui

文章目录 引言I war包部署flowable-ui下载war包配置Tomcat访问 flowable-uiII Docker启动flowable-ui并修改配置Docker启动flowable-ui修改配置访问Flowable UI界面。III 知识扩展加速源docker run -i -t -d 参数引言 Flowable 支持 BPMN 2.0 行业标准,同时提供了一些 Flowab…

Qt Creator 15.0.0如何更换主题和字体

1.打开Qt Creator 15.0.0 (Community)&#xff0c; 2.点击编辑栏3.点击Preferences... 4.修改主题&#xff0c;点击环境&#xff0c;修改Theme:栏 5.修改字体大小&#xff0c;点击文本编辑器&#xff0c;修改字号栏。&#xff0c;修改Theme:栏

【2025小年源码免费送】

&#x1f496;学习知识需费心&#xff0c; &#x1f4d5;整理归纳更费神。 &#x1f389;源码免费人人喜&#xff0c; &#x1f525;码农福利等你领&#xff01; &#x1f496;山高路远坑又深&#xff0c; &#x1f4d5;大军纵横任驰奔&#xff0c; &#x1f389;谁敢横刀立马行…

python学opencv|读取图像(四十一 )使用cv2.add()函数实现各个像素点BGR叠加

【1】引言 前序已经学习了直接在画布上使用掩模&#xff0c;会获得彩色图像的多种叠加效果&#xff0c;相关文章链接为&#xff1a; python学opencv|读取图像&#xff08;四十&#xff09;掩模&#xff1a;三通道图像的局部覆盖-CSDN博客 这时候如果更进一步&#xff0c;直接…

【面试总结】FFN(前馈神经网络)在Transformer模型中先升维再降维的原因

FFN&#xff08;前馈神经网络&#xff09;在Transformer模型中先升维再降维的设计具有多方面的重要原因&#xff0c;以下是对这些原因的总结&#xff1a; 1.目标与动机 高维映射空间&#xff1a;FFN的设计目的是通过一系列线性变换来拟合一个高维的映射空间&#xff0c;而不仅…