【Linux操作系统】关于系统中内存文件与进程的关系以及文件描述符fd、重定向的理解

news2025/1/16 19:10:25

目录

  • 一、关于文件和进程关系的简介
  • 二、了解文件操作的系统接口和C语言文件操作接口
    • 1.C语言文件操作接口
    • 2.文件操作的系统接口
  • 三、关于C语言接口和系统接口的关系
  • 四、文件描述符(fd)
    • 1.FILE* 结构体
    • 2.文件描述符表(fd的本质)
    • 3.文件fd的分配规则与默认打开的文件流
      • 默认打开的文件流 (0 & 1 & 2)
    • 4.重定向
      • 1.使用
      • 2.系统调用 dup2
      • 3.原理

一、关于文件和进程关系的简介

1.文件 = 文件内容 + 文件属性 即使空文件也有属性,由此得知,空文件也有大小
2.我们如果想访问文件,第一步都是要打开它,想要修改文件,都要通过执行代码以进程的方式完成修改
3.我们的CPU只能访问内存,因此文件必须被加载到内存中才能访问
4.一个进程可以打开多个文件,在一定时间内,系统会存在多个进程,但可能同时会存在更多被打开的文件,我们的系统是如何对这些文件进行管理的呢?
5.系统中是不是所有的文件都被进程打开了(内存文件)?并不是,没有被打开的文件在磁盘中(磁盘文件)
6.根据操作系统对文件先描述在组织的理论,我们可以猜测,操作系统内核中一定要有描述被打开文件的结构体,并用其定义

二、了解文件操作的系统接口和C语言文件操作接口

1.C语言文件操作接口

下面只是简单介绍几种常用接口,如想详细了解可以看(C语言文件接口详解)
1.打开关闭文件

FILE * fopen ( const char * filename, const char * mode );

mode表⽰⽂件的打开模式常见如:
在这里插入图片描述
以w方式打开文件,该文件会被文件清空

2.读取文件

size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);

从stream指向的文件中读取数据到ptr指向的数组中。size是每个元素的大小(以字节为单位),nmemb是要读取的元素数量。函数返回成功读取的元素数量。

int fscanf(FILE *stream, const char *format, ...);

从stream指向的文件中按照format指定的格式读取数据,并将数据存放到后续的参数中。成功时返回成功读取并赋值的输入项数量,失败时或到达文件末尾时返回EOF。

char *fgets(char *str, int n, FILE *stream);

从stream指向的文件中读取一行数据,并将其存储在str指向的数组中。n是数组的大小,用于限制读取的字符数(包括最后的空字符\0)。成功时返回指向str的指针,失败时或到达文件末尾时返回NULL。

3.写入文件

size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);

将ptr指向的数组中的数据写入到stream指向的文件中。size是每个元素的大小(以字节为单位),nmemb是要写入的元素数量。函数返回成功写入的元素数量。

int fprintf(FILE *stream, const char *format, ...);

根据format指定的格式,将数据写入到stream指向的文件中。成功时返回写入的字符数(不包括末尾的空字符),失败时返回负数。

int fputs(const char *str, FILE *stream);

将str指向的字符串(不包括末尾的空字符)写入到stream指向的文件中。成功时返回非负值,失败时返回EOF。

2.文件操作的系统接口

1.打开文件

#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

mode为文件的权限,用二进制设置如:666

open 函数具体使用哪个,和具体应用场景相关

如目标文件不存在,需要open创建,则第三个参数表示创建文件的默认权限

否则,使用两个参数的open。

2.读写
与C语言接口类似
1.read:从文件描述符中读取数据。

ssize_t read(int fd, void *buf, size_t count);

fd为文件描述符,buf为数据缓冲区,count为要读取的字节数。

2.write:向文件描述符中写入数据。

ssize_t write(int fd, const void *buf, size_t count);

与read函数类似,但数据流向相反。

三、关于C语言接口和系统接口的关系

1.首先文件要由进程管理,进程在启动的时候,会自动记录自己启动时所在的路径,所以创建文件一般都在当前路径下

2.上面的 fopen fclose fread fwrite 都是C标准库当中的函数,我们称之为库函数
open close read write lseek 都属于系统提供的接口,称之为系统调用接口
回忆操作系统概念时的一张图
在这里插入图片描述

操作系统一般不允许应用层的进程绕过操作系统直接访问硬件,所以文件读写时必定会经过操作系统,但只有系统调用接口可以访问操作系统,因此C语言中的库接口要想经过操作系统,就必须在库接口中封装系统调用接口,才能达到访问硬件的目的

四、文件描述符(fd)

通过对open函数的观察,我们得出文件描述符 fd 就是一个整数

为什么文件描述符是一个整数?又为何我们通过一个整数(fd)就可以去访问修改我们的文件呢?

1.FILE* 结构体

在一定时间段内,系统存在多个进程,也可能同时存在更多的被打开的文件

对于这些被打开的文件,操作系统要怎么管理呢?

答案是:先描述在组织

当一个进程打开一个文件时,会同时创建一个结构体,里面包含文件的各种信息,通过链表连接
就像下图一样

struct file
{
	//......
	int mode;//属性
	int flag;//方法集
	int pos;//缓冲区
	struct file* next;//连接其他结构体
}

在这里插入图片描述

2.文件描述符表(fd的本质)

文件的描述有了,进程又是如何组织管理文件的呢?

每一个进程打开多个文件,也就会得到多个FILE* 结构体指针,在进程中也存在着一个结构体管理者这些指针,叫做 文件描述符表
如下图所示:

task_struct
{
	//.......
	struct file_struct *files;
}

在这里插入图片描述

因此,在这里我们可以看到 fd的本质就是一个数组的下标

像之前的一些接口如 ssize_t read(int fd, void *buf, size_t count);中就是使用fd从自己进程的指针数组中去找到文件结构体进行访问

3.文件fd的分配规则与默认打开的文件流

当我们创建第一个最新的文件时,我们会发现,它的fd为3,为什么从3开始,而不是从0开始呢?

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

默认打开的文件流 (0 & 1 & 2)

在Linux进程中默认情况下会有三个缺省打开的文件描述符,也分别对应着C语言中默认打开的三个流(stdin,stdout,stderr)

分别为:

0:标准输入 stdin 通常对应键盘
1:标准输出 stdout 通常对应显示器
2:标准错误 stderr 通常对应显示器

在这里插入图片描述

这三个将文件描述符表的前三个下标占据,且文件描述符fd的分配规则为最小的没有被使用的数组下标,会被分配给最新打开的文件,因此新文件的文件描述符从3开始

无论你是使用哪种语言,都会有有各自输入输出等流来打开文件,但是操作系统中只认文件描述符,因此,各种语言的流中都会封装文件描述符fd,来保证跨平台性。

4.重定向

按上述所说,我们平时要不就是默认从键盘输入要么就是从屏幕输出

假如我想变化一下呢,我能不能把应该输出到显示器的数据输入到文件中呢

因此,Linux提供了重定向的方式

它允许你将命令的标准输入(stdin)、标准输出(stdout)或标准错误输出(stderr)从一个默认的位置(如键盘、屏幕)重定向到另一个位置(如文件、另一个命令的输入等)。

重定向是通过特定的符号来实现的。

1.使用

标准输出重定向(stdout)

  • 使用 > 符号将命令的标准输出重定向到文件。如果文件已存在,它会被覆盖;如果文件不存在,它会被创建。
 `ls > files.txt`
  • 使用 >> 符号将命令的标准输出追加到文件的末尾,而不是覆盖它
echo "Hello, World!" >> greetings.txt

输入重定向(stdin)

  • 输入重定向使用 < 符号,但它不如输出重定向常用,因为输入通常来自键盘或脚本。然而,你可以将文件的内容作为命令的输入
 ls | grep "txt"

上面的命令等同于 sort file.txt

2.系统调用 dup2

用于复制一个现有的文件描述符到另一个文件描述符,如果目标文件描述符已经打开,则先关闭它。

用于重定向输入、输出或错误输出流。

#include <unistd.h>  
#include <fcntl.h>  
  
int dup2(int oldfd, int newfd);

oldfd:要复制的文件描述符。
newfd:目标文件描述符。

#include <stdio.h>  
#include <stdlib.h>  
#include <unistd.h>  
#include <fcntl.h>  
  
int main() {  
    int fd;  
  
    // 打开文件用于写入,如果文件不存在则创建它  
    fd = open("output.txt", O_WRONLY | O_CREAT | O_TRUNC, 0666);  
    if (fd == -1) {  
        perror("open");  
        exit(EXIT_FAILURE);  
    }  
  
    // 将标准输出重定向到文件  
    if (dup2(fd, STDOUT_FILENO) == -1) {  
        perror("dup2");  
        close(fd); // 不要忘记关闭文件描述符  
        exit(EXIT_FAILURE);  
    }  
  
    // 关闭原始的文件描述符(现在不需要了,因为已经通过dup2复制了)  
    close(fd);  
  
    // 现在,所有的printf输出都会写入到output.txt文件中  
    printf("Hello, World!\n");  
  
    // 注意:程序结束时,文件不会自动关闭。你可能需要在程序的最后关闭它,  
    // 但由于我们在这里重定向了stdout,所以实际上stdout会在程序结束时自动刷新并关闭。  
    // 然而,如果你直接操作文件描述符(比如fd),那么你需要显式地关闭它。  
  
    return 0;  
}

成功时,dup2 返回 newfd。
出错时,返回 -1 并设置 errno 以指示错误。

3.原理

原理其实很简单,一张图即可说明
在这里插入图片描述

和上面的dug2类似,将想要重定向的文件替换到想要替换的流即可

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

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

相关文章

透明显示屏方案介绍

透明显示屏方案是一种创新的显示技术解决方案&#xff0c;它结合了透明材料和高性能显示技术&#xff0c;实现了在显示内容的同时保持屏幕背后物体或场景的可见性。以下是对透明显示屏方案的详细介绍&#xff1a; 一、技术原理 透明显示屏方案主要采用了LED透明屏和OLED透明屏两…

基于PHP+MySQL组合开发的微信活动投票小程序源码系统 带完整的安装代码包以及搭建部署教程

系统概述 在当今数字化时代&#xff0c;微信作为社交媒体的巨头&#xff0c;为企业和个人提供了丰富的互动营销平台。其中&#xff0c;投票活动作为一种有效的用户参与和互动方式&#xff0c;被广泛应用于各种场景。为了满足这一需求&#xff0c;我们推出了一款基于PHPMySQL组…

zabbix“专家坐诊”第249期问答

问题一 Q&#xff1a;zabbix server服务每次重启监控主机就会触发大量的“10分钟未获取到数据”的告警&#xff0c;同时还会触发zabbix的history进程繁忙的告警。&#xff08;后面检查实际上监控主机在告警时间段内是有数据的&#xff09;感觉是server一重启&#xff0c;数据库…

Python | ValueError: invalid literal for int() with base 10: ‘example’

Python | ValueError: invalid literal for int() with base 10: ‘example’ 在Python编程中&#xff0c;遇到ValueError: invalid literal for int() with base 10: example这样的错误通常意味着你试图将一个字符串转换为整数&#xff0c;但该字符串包含非数字字符。这种错误…

美团 AIGC产品经理面经(已拿 offer)

背景&#xff1a;211本科毕业&#xff0c;毕业之后在北京一家中型电商公司做了3年商家后台产品经理&#xff0c;目前通过老薛的朋友关系拿到了美团的offer。 目前还有几家在面试流程中&#xff0c;继续加油&#x1f4aa; 美团AIGC产品面经-业务面 &#x1f4a5;1、自我介绍&a…

找不到vcruntime140_1.dll,无法执行此代码

电脑运行某些软件提示&#xff1a;由于找不到vcruntime140_1.dll,无法继续执行代码 解决方法 1、下载这个软件 https://download.csdn.net/download/szdenny/89605688 2、 通过这个网址下载软件修复&#xff1a;http://xn--dll-8n0e103b00dgy4e.site/

前端:Vue学习 - 智慧商城项目

前端&#xff1a;Vue学习 - 智慧商城项目 1. vue组件库 > vant-ui2. postcss插件 > vw 适配3. 路由配置4. 登录页面静态布局4.1 封装axios实例访问验证码接口4.2 vant 组件 > 轻提示4.3 短信验证倒计时4.4 登录功能4.5 响应拦截器 > 统一处理错误4.6 登录权证信息存…

ArcGIS导出的shp不带prj文件怎么办?

0序 遇到了好多个做测绘的朋友&#xff0c;拿到的shp文件都没有prj文件&#xff0c;在图新地球当中无法加载。 而prj文件是其他软件解析shp&#xff0c;和地图做叠加的核心。否则就不知道shp要素的坐标按照什么坐标去解析。 经过排查发现&#xff0c;大部分是在arcgis中导出sh…

数据同步策略概览

数据同步在业务开发中比较普遍&#xff0c;例如 订阅MySQL的binlog将数据同步至异构数据库。数据同步方案需要考虑一下几点&#xff1a; 数据实时性要求数据量级是否有数据转换逻辑 可分为两种模式 发布订阅模式&#xff1a;分为订阅数据库log还是订阅应用层发的消息点对点模…

适合印刷企业使用的MES管理系统具备哪些特点

在当今竞争激烈的印刷行业中&#xff0c;提高生产效率、优化资源配置、确保产品质量与交期已成为企业生存与发展的关键。为此&#xff0c;引入一套高效、智能的印刷企业MES管理系统显得尤为重要。MES管理系统作为连接企业资源计划ERP系统与车间生产现场的桥梁&#xff0c;其设计…

Linux下的nc命令:网络工具的瑞士军刀

在 Linux 系统中&#xff0c;有许多强大的网络工具可用于网络连接、数据传输和端口扫描。其中一个非常强大的工具是 nc&#xff0c;也称为 Netcat&#xff0c;被称为网络工具的瑞士军刀&#xff0c;因为它可以执行各种网络任务。本文将深入探讨 nc 命令的使用方法&#xff0c;提…

第127天:内网安全-隧道搭建穿透上线FRPNPSSPPNgrokEW 项目

目录 案例一&#xff1a;内网穿透-Ngrok-入门-上线 案例二&#xff1a;内网穿透-Frp-简易型-上线 案例三&#xff1a; 内网穿透-Nps-自定义-上线 案例四&#xff1a;内网穿透-Spp-特殊协议-上线 案例一&#xff1a;内网穿透-Ngrok-入门-上线 这里我是用了一台云服务器&…

zy青岛实训day19 8/1

接着昨天的 npm run serve 构建项目 npm run build ls ls dist/ vim dist/index.html [rootweb eleme_web]# cd /usr/local/nginx/conf/ [rootweb conf]# ls 将静态的项目移动到nginx中 [rootweb nginx]# cd conf.d/ [rootweb conf.d]# ls qd.conf [rootweb conf.…

信息学奥赛初赛天天练-52-CSP-J2019基础题3-抽屉原理、鸽巢原理、乘法原理、二叉树遍历、前序遍历、中序遍历、后序遍历

PDF文档公众号回复关键字:20240801 2019 CSP-J 基础题3 单项选择题&#xff08;共15题&#xff0c;每题2分&#xff0c;共计30分&#xff1a;每题有且仅有一个正确选项&#xff09; 11 新学期开学了&#xff0c;小胖想减肥&#xff0c;健身教练给小胖制定了两个训练方案。 …

个人的知识点小分享

type查看命令类型&#xff08;内建命令/外部命令&#xff09; [rootlocalhost ~]# type cd cd is a shell builtin [rootlocalhost ~]# type ls ls is aliased to ls --colorauto Ps 命令 --help 查看命令的常见选项 info 命令 #比man更详细的帮助命令。 回车…

arduino程序-MC猜数字1(基础知识)

arduino程序-MC猜数字1&#xff08;基础知识&#xff09; 1-18 MC猜数字0-介绍1-19 MC猜数字1-电路搭建电路图所需元件10根杜邦线&#xff08;公对公&#xff09;10根左右面包板跳线数码管按键电阻1个&#xff08;200~500欧姆&#xff09;面包板Arduino UNO R3*1 搭建电路相关程…

实验2-4-4 求简单交错序列前N项和

//实验2-4-4 求简单交错序列前N项和//计算序列 1 - 1/4 1/7 - 1/10 ... 的前N项之和。 #include<stdio.h> #include<math.h> int main(){int n;scanf("%d",&n);//输入在一行中给出一个正整数N。double sum0;for(int i1;i<n*3;i3){//i3>题目…

maven项目容器化运行之4-子模块利用Jenkins和maven使用docker插件调用远程docker构建服务

一.背景 之前期望把开发和部署分开&#xff0c;在上篇文章maven项目容器化运行之3-优雅的利用Jenkins和maven使用docker插件调用远程docker构建服务并在1Panel中运行-CSDN博客已经实现了。主要思路是开发配置了pom文件&#xff0c;但是不管docker镜像打包。提交代码库后&#x…

马丁短链03用户信息脱敏

为什么后端脱敏&#xff1a; 因为如果给前端做&#xff0c;请求返回数据之后未脱敏&#xff0c;只在网页显示上脱敏&#xff0c;攻击者可以做一些简单请求直接看到返回信息&#xff0c;只能防一些小白。所以要在服务器这里做。 复杂的方法&#xff1a; 在controller层设置自定…

AI学习(1)软件的选择,cuda和pytorch的安装

文章目录 1.使用VScode开发&#xff0c;结合anaconda配置python环境2.安装pytorch库3.深度学习相关的库1.numpy&#xff08;科学计算库&#xff09;2.pandas(数据分析处理库)3.matplotlib&#xff08;可视化库&#xff09;4.seaborn&#xff08;可视化库&#xff09; 1.使用VSc…