文件的原理和应用

news2024/9/20 22:49:05

常识:

1 文件包括属性和内容

2 文件有打开和未打开文件,

3 本文先讨论谁打开的文件,以及如何管理已经打开的文件

一 回忆c接口

1 fopen

        我们在test.c里面用一下fopen函数,不存在打开的文件会默认创建,那为什么默认新建在当前目录下是因为cwd,而不是PWD,我们知道PWD是环境变量,如果我们去到其它工作目录,PWD会变,但是CWD不变,此时再运行一下test.c,此时文件还是会创建在CWD存的路径下,而不随着环境变量改变而变化。

2 fwrite

        fwrite函数可以往文件写数据,值得一提的是fwrite的size参数,这个是要写入的字节数,我们大部分时候都是往文件写个字符串,例如"hello linux",有时候size传strlen("hello linux"),有时候传sizeof(hello linux),我们会发现sizeof多写入的\0被文件识别为乱码,这说明一个问题,字符串结尾有\0这个字符是c语言的规定,文件是不认这个\0是字符的。

二 文件操作和系统调用

        fwrite库函数一定封装了系统调用因为文件是在磁盘上的,fwirte要往硬件写数据,那不就相当于访问硬件的资源,由于操作系统不相信用户,所以fwrite一定不是直接把数据弄给硬件,而是通过操作系统的接口将数据传给硬件。接下里就来认识认识几个系统调用。

        1 认识open

        从fopen的名字上看,我们也知道fopen封装的是open,接下来就看看open的参数和返回值。man 2 open就可从手册调出open的信息。

显然,函数1是函数2的的子集合,我们只要说清楚了函数2,函数1的使用也就明白了。

参数1 文件名,不带路径应该是默认在当前路径下找。

参数2 flags是什么呢?

        

        我们要给flags传的是上面图片中的宏,这些宏都表示一个一个的整数,接下来就介绍介绍这些宏的意义,以及如何使用O_RDONLY表示open以只读方式打开,O_WRONLY表示open以写方式打开,  而O_RDWR则表示以读写方式打开,这三个宏最好只出现一个,至于其它的宏O_APPEND,这个是表示向文件写时以追加的方式去写。

使用:

| :按位或?这个使用又是啥意思呢? 

        举个例子,O_RDONLY可能是用0001来表示,O_WRONLY则是0010O_RDWR则是0100来表示,同理得,O_APPEND就要用1000来表示,只用了一个比特位就能唯一表示一个宏,这样的设计非常巧妙,首先我们可能会传多个宏,设计者没有用可模板参数来接收,而是只用一个整型,因为我们可以对传的参数进行按位或,这样只要对按位或的结果一分析,就知道你打开文件是要读还是写了,所以flag的类型就只是个朴素的int,可其实里面门道也不少。

参数3 权限初始化,因为我们open发现打开文件不存在,要创建文件,此时文件的权限是要指定的,不然会给一个初始值,但这个初始值如下图。

       2 认识write和read

write和read就简单多了。

write:往fd这个文件描述符对应的文件写入buf数组中的元素,字节数为count。

read:从fd这个文件描述符对应的文件读取count个字节的数据,写入buf数组中。

        现在我们就能解释:现在我们就可以解释为什么fwrite就传一个"w"可以实现清空写,以及创建文件,"w+"为什么能实现追加写,就是因为在底层封装了这些宏,然后操作系统识别到了,在调用系统调用的时候传了给flag传了不同的宏,至于返回值会在下面访问文件的本质中提及。

三 访问文件的本质

        open的返回值-文件描述符,这个文件描述符怎么是int类型呢,我fopen用的可是FILE*,这两者有什么关系吗?

        先来看看操作系统如何管理文件,首先操作系统打开的文件有很多,这些必然会被操作系统管理,操作系统管理文件,就像管理进程一样,只要用一个file结构体描述文件即可,根本就不需要管文件内容,这样在系统内核处,就又增加了一个数据结构将所有的file结构体管理起来诶,不对啊,文件不是进程打开的吗,那不是应该进程管理吗,如果仅仅是被进程管理,那如果进程出异常了,被kill了,这些文件不就丢失了?所以系统必须也要管理。如下图:

        好吧,既然上面是系统管理文件的方式,那进程呢怎么管理呢?

        所以会有一个files_struct(这个和FILE*可不相同)来管理,这个结构体内部会有一个数组,数组每元素就是一个文件指针,而文件描述符就是数组下标,所以说一个文件描述符一定对应一个文件,当然多个文件描述符可以对应同一个文件(file结构体内部肯定是会有引用计数记录的)也就是说底层进程是通过下标来找文件指针,从而找到文件的,所以FILE*内部一定封装了文件描述符,不然系统调用找不到文件。

        我们发现所有语言写的代码运行起来都要默认打开三个文件,stdin,stdout,stderror,因为系统就要这样做,系统设计这就认为开机后天然需要键盘,显示器文件,所以就要打开,而所有语言写的代码不管写了啥,形成进程后,就会把已经打开的文件填到files_struct内,所以程序一运行,该数组内就有了三个元素。

        既然stderror和stdout都是指向显示器文件,它们的区别是什么,我想也就是其内部的封装的文件描述符不同,当我们close(1),printf就用不了了,但是perror还可以向显示器打印。

四 重定向

        周边小知识:write写的时候如果不close,一直写,那就会一直往后写,而不是覆盖,open以追加方式写,指的是第一次write写的时候从哪开始写。

1 文件描述符的分配规则

        自数组开头遍历,在数组中最先遇到的空格位置的下标,就是被分配的文件描述符。先前已经说了系统会打开两个文件(说打开三个是方便理解),这两个文件是键盘,显示器,而显示器被打开了两次,在files_struct内的数组就会有三个文件描述符,其中0存的是键盘文件指针,1,2存的都是显示器文件指针,我前面说多个文件描述符可以对应同一个文件,这就是实实在在的例子。

2 手动实现重定向

        输出重定向就是printf本来是要写给显示器的,但是由于close(1),然后又打开了myfile.txt后占用了一号位(这就验证了文件描述符的分配规则)。

    1 #include<stdio.h>
    2 #include<stdlib.h>
    3 #include<unistd.h>
    4 #include<string.h>
    5 #include <sys/types.h>
    6 #include <sys/stat.h>
    7 #include <fcntl.h>
    8 int main()
    9 {
   10     printf("我的id:%d\n",getpid());
   11     close(1);
W> 12     int fd = open("myfile.txt", O_CREAT|O_WRONLY,0666);
   13     printf("我的id:%d\n",getpid());                                                
   14     return 0;
   15 }
  ~

所以两句printf就只有一句输出,因为第二句printf就变成往myfile.txt输出了。

        这也侧面说明在操作系统看来,往显示器写和普通的文件没有区别,而printf内部用的stdout一定是封装了1号文件描述符,这是编码定死的,printf也不管这个标识符对应的文件变了没,拿到就写,就有了输出重定向这种乌龙。

3 系统调用dup2

        虽然可以先close,再打开文件实现重定向,但这样的代码还是不如直接调用系统调用那么优雅,直接上代码,看看使用。结果一致。

问题1 oldfd和newfd谁覆盖谁显然从先前的例子来看,是oldfd上的内容覆盖到newfd的内容,本质是数组对应下标上元素,也就是文件指针的拷贝。

读者可以尝试进行输入重定向

同理也就是对0号位置下标做手脚

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

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

相关文章

RabbitMQ 的网页界面操作说明

启动 上面给用户添加了角色和权限&#xff0c; 我们就可以登录了 先手动创建两个队列&#xff0c;然后再把这两个队列和交换机绑定&#xff0c;就可以发布消息 回到队列中看看有什么变化 队列中显示绑定了交换机 再看一下队列中发生的变化 可以看到队列中收到了信息

代码随想录二刷 | 链表 |环形链表II

代码随想录二刷 &#xff5c; 链表 &#xff5c;环形链表II 题目描述解题思路 & 代码实现判断链表是否有环如何找到环的入口 题目描述 142.环形链表II 给定一个链表的头节点 head &#xff0c;返回链表开始入环的第一个节点。 如果链表无环&#xff0c;则返回 null。 如…

千梦网创:创业一定要学会打造自己的榜样圈

一、状态 最近一直在学习刘克亚老师的书籍和课程。 克亚老师“国际自由族”的概念实际上就是实现“工作自由”。 财务自由只是一个奋斗目标&#xff0c;但“工作自由”是一种可实现的工作状态。 这种工作状态有一个特征就是全力打造一套能够无限趋近于“全自动”的赚钱系统。…

超详细 | 实验室linux服务器非root账号 | 安装pip | 安装conda

登录实验室公用服务器&#xff0c;个人账号下&#xff08;非root&#xff09;是空的&#xff0c;啥也没有&#xff0c;想安装下pip和conda。 转了一圈&#xff0c;好像没太有针对这个需求写具体博客的&#xff0c;但有挺多讲直接在root下安的&#xff08;用的应该是个人虚拟机&…

代码随想录二刷 | 链表 |链表相交

代码随想录二刷 &#xff5c; 链表 &#xff5c;链表相交 题目描述解题思路 & 代码实现 题目描述 160.链表相交 给你两个单链表的头节点 headA 和 headB &#xff0c;请你找出并返回两个单链表相交的起始节点。如果两个链表没有交点&#xff0c;返回 null 。 题目数据 保…

透视未来:现代发电厂地区可视化与智慧能源的结合

随着全球能源消费的不断增长&#xff0c;电力需求也在不断上升。作为能源行业的重要组成部分&#xff0c;现代发电厂扮演着不可替代的角色。而现代发电厂的数据管理和监控系统&#xff0c;则是确保其安全、高效、稳定运行的重要手段。在这个背景下&#xff0c;现代发电厂地区可…

Python+Selenium安装及环境配置手把手教会你

前言 Selenium是一个用于web自动化测试的框架&#xff0c;在使用Ajax请求数据的页面中&#xff0c;会出现 sign ,token等密钥&#xff0c;如果考虑去破解可能花费的精力较多&#xff0c;所以考虑借助使用Selenium框架来实现数据爬取。 Selenium 简介 1. 1&#xff0c;组件✨ …

SMBGhost_RCE漏洞(CVE-2020-0796永恒之黑)

https://blog.csdn.net/qq_45372008/article/details/106980409 https://zhuanlan.zhihu.com/p/374949632 SMB 3.1.1协议处理某些请求的方式中存在远程执行代码漏洞&#xff0c;可能被攻击者利用远程执行任意代码。该漏洞的后果十分接近永恒之蓝系列&#xff0c;都利用Windows …

不看后悔系列 | 秒做BI报表,告别低效分析

根据经验来看&#xff0c;做企业数据分析&#xff0c;通常是由业务提出需求&#xff0c;交给IT去取数开发&#xff0c;当业务通过分析报表有了新的需求时&#xff0c;仍需交给IT去取数分析&#xff0c;这就导致业务的分析效率低。进入大数据时代&#xff0c;这样的低效数据分析…

【linux】安装telnet

Telnet Telnet协议是TCP/IP协议族中的一员&#xff0c;是Internet远程登录服务的标准协议和主要方式。它为用户提供了在本地计算机上完成远程主机工作的能力。在终端使用者的电脑上使用telnet程序&#xff0c;用它连接到服务器。终端使用者可以在telnet程序中输入命令&#xf…

python练习题(markdown中的60道题)

1.Demo01 摄氏温度转化为华氏温度 celsius float(input(输入摄氏温度&#xff1a;)) fahrenheit (9/5)*celsius 32 print(%0.1f 摄氏温度转为华氏温度为 %0.1f % (celsius, fahrenheit))结果&#xff1a; 2.Demo02 计算圆柱体的体积 h, r map(float, input().split())# …

python命令行交互 引导用户输入一个数字

代码 以下代码将在命令行中&#xff0c;引导用户选择一个数字&#xff0c;并反馈用户输入的值 # -*- coding:UTF-8 -*- """ author: dyy contact: douyaoyuan126.com time: 2023/11/22 15:51 file: 引导用户输入一个数字.py desc: xxxxxx """#…

VMware Workstation系列:Windows10 优化VMware虚拟机运行速度总结(单台、多台-ESXI)

Windows10 优化VMware虚拟机运行速度总结 一. 单台或两台同时运行前言&#xff1a;优化方法环境&#xff1a; 1、清除多余快照2、清理磁盘。3、虚拟机全局设置5、设置“优先级”6、设置“设备”7、编辑虚拟机设置8、分配合适的内存和CPU 二. 多台并行背景&#xff1a;一. 下载1…

用css实现原生form中radio单选框和input输入框的hover样式以及聚焦focus的样式

一.问题描述&#xff1a;用css实现原生form中radio单选框和input的hover已经focus的样式 在实际的开发中&#xff0c;一般公司ui都会给效果图&#xff0c;比如单选按钮radio样式&#xff0c;input输入框hover的时候样式&#xff0c;以及focus的时候样式&#xff0c;等等&#…

有哪些好用的CFD软件?怎么选?

ANSYS Fluent和COMSOL Multiphysics以及OpenFOAM这3款CFD软件哪个好&#xff1f;cfd软件中哪款最实用&#xff1f;cfd软件有哪些&#xff1f;今天就给大家带来这几款CFD软件对比分析&#xff0c;一起来看看吧。 ANSYS Fluent ANSYS Fluent 是一种流行的计算流体动力学 (CFD) …

时态图根据时间轴动态播放热力图

效果图如下&#xff1a; <!DOCTYPE html> <html><head><title>时态图</title><meta charset"utf-8" /><meta name"viewport" content"widthdevice-width, initial-scale1.0" /><!-- 引入样式 --&g…

用于 syslog 收集的协议:TCP、UDP、RELP

系统日志是从 Linux/Unix 设备和其他网络设备&#xff08;如交换机、路由器和防火墙&#xff09;生成的日志 可以通过将 syslog 聚合到称为 syslog 服务器、syslog 守护程序或 syslogd 的服务器来集中 syslog。在TCP、UDP和RELP协议的帮助下&#xff0c;系统日志从设备传输到系…

VMware 系列:Vmware Workstation 嵌套 Vmware Vsphere Hypervisor(ESXI)部署后虚拟机无法上网的问题

【背景】 现有日常机器配置结构:NUCmini主机(硬件)->Deepin Linux(物理机操作系统,日常办公用)->Vmware Workstation 16->N多虚拟机 最近Vmware发布了Vsphere Hypervisor 8,也就是我们常说的ESXI 8,想要测试下新的系统,后面把自己的服务器从ESXI 7迁移到ESXI 8…

用HALCON标定助手对相机进行标定

任务要求&#xff1a; 已知相机镜头焦距f为8mm&#xff0c;相机单个CCD像素在水平和竖直两个方向上的尺寸均为3.75微米&#xff0c;相机为普通透光镜头和面阵相机&#xff0c;对相机进行标定&#xff0c;测量相机的内外参数。 操作步骤&#xff1a; 1. 在HALCON中运行gen_ca…