【Linux】从零认识文件操作

在这里插入图片描述
送给大家一句话:

要相信,所有的不美好都是为了迎接美好,所有的困难都会为努力让道。
—— 简蔓《巧克力色微凉青春》

开始理解基础 IO 吧!

  • 1 前言
  • 2 知识回顾
  • 3 理解文件
    • 3.1 进程和文件的关系
    • 3.2 文件的系统调用
      • open
      • write
      • 文件 fd 值
    • 3.3 语言层如何理解
  • Thanks♪(・ω・)ノ谢谢阅读!!!
  • 下一篇文章见!!!

1 前言

在C语言已经掌握文件操作的一些接口,接下来我们来从操作系统的层面来理解文件操作!!!
基础IO的篇章我们将讲解以下内容:

  1. 复习C文件IO相关操作
  2. 认识文件相关系统调用接口
  3. 认识文件描述符,理解重定向
  4. 对比fd和FILE,理解系统调用和库函数的关系
  5. 理解文件系统中inode的概念
  6. 认识软硬链接,对比区别
  7. 认识动态静态库,学会结合gcc选项,制作动静态库

2 知识回顾

C语言中要进行文件操作,就一定要先打开这个文件:fopen(),并用一个文件指针来接收
例如:FILE* fp = fopen("log.txt","w")
打开也有可能会失败,所以还要检查fp是否为空指针。当我们使用完文件之后一定一定要关闭文件:fclose(fp)

我们要进行文件操作,前提是我们的程序跑起来了!文件打开和关闭,是CPU在执行我们的程序。所以可以推断出来:

  • 打开文件的本质是进程打开文件!!!
  • 文件没有被打开的时候,文件在哪里??? 当然是磁盘了
  • 进程可以打开多个文件!!! (系统中同样可以存在多个进程) 很多的情况下,OS内部存在大量被打开的文件!那操作系统就要对打开的文件进行管理!! (那么每个打开的文件在OS内部都存在一个对应描述文件属性的结构体,类似PCB
  • 文件 = 属性 + 内容
  • 注意文件写入方式:
r   Open text file for reading.The stream is positioned at the beginning of the file.r+  Open for reading and writing.The stream is positioned at the beginning of the file.w   Truncate(缩短) file to zero length or create text file for writing.The stream is positioned at the beginning of the file.w+  Open for reading and writing.The file is created if it does not exist, otherwise it is truncated.The stream is positioned at the beginning of the file.a   Open for appending (writing at end of file).The file is created if it does not exist.The stream is positioned at the end of the file.a+  Open for reading and appending (writing at end of file).The file is created if it does not exist. The initial file positionfor reading is at the beginning of the file,but output is always appended to the end of the file.

3 理解文件

3.1 进程和文件的关系

3.2 文件的系统调用

open

各个语言的文件接口基本都是不一样的,那么语言之间有没有共性呢???
我们来看一个系统调用:open(),我们先认识使用一下:

int open(const char *pathname, int flags);
int open(const char *pathname, int flags, mode_t mode);

第一个参数和C语言fopen的第一个参数一致(表示文件路径或当前目录下的文件名)
第二个参数表示想怎样打开文件,传入的是标志位
第三个参数表示创建文件的权限
会返回一个数字表示是否打开成功。

  1 #include<sys/types.h>  2 #include<sys/stat.h>  3 #include<stdio.h>  4 #include<fcntl.h>  5   6 int main()  7 {  // 以只读形式打开 , 文件不存在就创建8   int fd = open("log.txt",O_WRONLY|O_CREAT);  9   if(fd < 0)  10   {  11     perror("open");  12     return 1;  13   }                                                                                                                                                                           14 }   

运行代码:
在这里插入图片描述
可以看的我们成功创建了一个新文件,但是文件的权限好像不对(这里因为我们没有设置对应权限,所以是乱码!)
所以才有了第三个参数,来帮助我们确定权限
int fd = open("log.txt",O_WRONLY|O_CREAT,0666); 我们在来看看
在这里插入图片描述
哎呦???怎么权限还是不对,我们设置的是666应该是rw-rw-rw-啊???这是因为创建的文件会收到文件掩码的影响:
在这里插入图片描述
所以会出现这样的情况,那怎么解决呢?

我们可以使用umask()系统调用,动态修改掩码值(只在该进程中起作用),来达到我们预期的结果:

  1 #include<sys/types.h>2 #include<sys/stat.h>3 #include<stdio.h>4 #include<fcntl.h>5 6 int main()7 {8   umask(0);                                                                                                                                                                   9   int fd = open("log.txt",O_WRONLY|O_CREAT,0666);                                                             10   if(fd < 0)                                                                                                  11   {                                                                                                           12     perror("open");                                                                                           13     return 1;                                                                                                 14   }                                                                                                           15 } 

这样就创建出来我们预期的效果了!!!

我们再来看看 flag 标志位,它是一个32位的整数,每个比特位代表一个对应功能(OS常用的系统调用接口的常用方法),也就是位图!!!每个宏定义都是一个对应比特位设置为1,想要实现多个功能就进行 | 按位与操作就可以了!!!

常用的标志位参数:
O_RDONLY: 只读打开
O_WRONLY: 只写打开
O_RDWR : 读,写打开
上面三个常量,必须指定一个且只能指定一个O_CREAT : 若文件不存在,则创建它。需要使用mode选项,来指明新文件的访问权限
O_APPEND: 追加写

write

接下来我们写入来试试。

  1 #include<sys/types.h>2 #include<sys/stat.h>3 #include<stdio.h>4 #include<fcntl.h>5 6 int main()7 {8   umask(0);9   int fd = open("log.txt",O_WRONLY|O_CREAT,0666);10   if(fd < 0)11   {12     perror("open");13     return 1;14   }15 16   const char* message = "hello linux file!\n";17   write(fd , message,strlen(message));18 19   close(fd);20   return 0;                                                                                                                                                                   21 }    

这样就成功写入进去了(注意没有写入\0哦)
在这里插入图片描述
但是我们在写入aaaa时会发现,原本文件并没有清空,也就是open默认不会清空文件!!!,这时我们加入新的标记位O_TRUNC,就能打开文件就清空了!现在就不会出现叠加的情况了!通过不同的标识位可以做到不同功能(比如追加写入)

文件 fd 值

接下来我们来认识一下文件fd:

#include<sys/types.h>  2 #include<sys/stat.h>  3 #include<stdio.h>  4 #include<fcntl.h>  5 #include<string.h>  6   7 int main()  8 {  9   int fda = open("loga.txt",O_WRONLY|O_CREAT|O_TRUNC);  10   printf("fda: %d\n",fda);  11   12   int fdb = open("logb.txt",O_WRONLY|O_CREAT|O_TRUNC);  13   printf("fda: %d\n",fdb);  14     15   int fdc = open("logc.txt",O_WRONLY|O_CREAT|O_TRUNC);  16   printf("fda: %d\n",fdc) ;   17   return 018 }  

来看效果:
在这里插入图片描述
每个文件都有对应的不同的fd值(类似进程的 pid),为什么是从3开始的呢,因为0 1 2 ,都是已经设置好的文件:

  • 0 : 标准输入 – 键盘
  • 1 : 标准输出 – 显示器
  • 2 : 标准错误 – 显示器

在语言层(比如C语言),也会默认打开这三个(stdin stdout stderr)。我们使用文件对应的fd值,也可以实现写入操作了。
那么在操作系统内部,是如何实现的呢?
文件的管理类似进程管理,会有对应的struct filel来进行管理,而且多个进程可能打开同一个文件,所以进程里也一定有管理该进程打开的文件的结构体(struct files_struct),里面包含一个指针数组,每个指针都指向对应的文件,数组的下标也就是每个文件的fd值,所以上层的系统调用使用fd值(数组下标)就能访问对应文件!!!
在这里插入图片描述
这时也就可以总结一下open系统调用做了哪些事情:

  1. 创建file
  2. 开辟文件缓冲区的空间,加载文件数据
  3. 查进程的文件描述符表(struct files_struct *file)
  4. file 地址,填入对应表的下表中
  5. 返回下标(fd)

3.3 语言层如何理解

C语言中FILE其实是一个结构体类型,内部一定会封装文件fd!!!来看

#include<sys/types.h>  2 #include<sys/stat.h>  3 #include<stdio.h>  4 #include<fcntl.h>  5 #include<string.h>  6   7 int main()  8 {  9   10   printf("stdin->fd: %d\n",stdin->_fileno);  11   printf("stdin->fd: %d\n",stdout->_fileno);  12   printf("stdin->fd: %d\n",stderr->_fileno);  13   14   FILE* fp = fopen("log.txt","w");  15   if(fp == NULL) return 1;  16   printf("fd : %d\n",fp->_fileno);  17   18   FILE* fp1 = fopen("log1.txt","w");  19   if(fp1 == NULL) return 1;  20   printf("fd : %d\n",fp1->_fileno);  21   22   FILE* fp2 = fopen("log2.txt","w");  23   if(fp2 == NULL) return 1;  24   printf("fd : %d\n",fp2->_fileno);    25   return 026 }

来看运行效果:
在这里插入图片描述
怎么样,我们的猜测没有问题!!!所以语言层的文件操作函数,本质底层是对系统调用的封装!通过不同标志位的封装来体现w r a+等不同打开类型!
我们在使用文件操作时,一般都要使用语言层的系统调用,来保证代码的可移植性。因为不同系统的系统调用可以会不一样!

下一篇文章我们来看文件操作的应用!!!

Thanks♪(・ω・)ノ谢谢阅读!!!

下一篇文章见!!!

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

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

相关文章

OpenHarmony实战:小型系统平台驱动移植

在这一步&#xff0c;我们会在源码目录//device/vendor_name/soc_name/drivers目录下创建平台驱动。 建议的目录结构&#xff1a; device ├── vendor_name │ ├── drivers │ │ │ ├── common │ │ │ ├── Kconfig # 厂商驱动内核菜单入口 │ …

七大开源基金会联合制定符合 CRA 法案的共同标准

欧洲议会上个月通过的《欧洲网络弹性法案》(CRA) 制定通用规范和标准 Apache 软件基金会、Blender 基金会、Eclipse 基金会、OpenSSL 软件基金会、PHP 基金会、Python 软件基金会 和 Rust 基金会 这项工作由 Eclipse 基金会牵头&#xff0c;旨在建立基于现有开源最佳实践的安全…

9.图像中值腐蚀膨胀滤波的实现

1 简介 在第七章介绍了基于三种卷积前的图像填充方式&#xff0c;并生成了3X3的图像卷积模板&#xff0c;第八章运用这种卷积模板进行了均值滤波的FPGA实现与MATLAB实现&#xff0c;验证了卷积模板生成的正确性和均值滤波算法的MATLAB算法实现。   由于均值滤波、中值滤波、腐…

leet hot 100-13 最大子数组和

53. 最大子数组和 原题链接思路代码 原题链接 leet hot 100-10 53. 最大子数组和 思路 生成一个数字来记录last 表示前面数字全部之和与0取最大值 如果大于0 就加上如果不大于0 就不管 从当前位置从新开始遍历计算 时间复杂度O(n) 空间复杂度(1) 代码 class Solution {…

JVM剖析

0.前言 Java 是当今世界使用最广泛的技术平台之一。使用 Java 或 JVM 的一些技术包括&#xff1a; Apache spark用于大数据处理&#xff0c;数据分析在JVM上运行;用于数据流的Apache NiFi在内部使用的也是 JVM;现代 Web 和移动应用程序开发中使用的React native使用 的也包含…

HTTPS RSA 握手解析(计算机网络)

传统的 TLS 握手基本都是使用 RSA 算法来实现密钥交换的&#xff0c;在将 TLS 证书部署服务端时&#xff0c;证书文件其实就是服务端的公钥&#xff0c;会在 TLS 握手阶段传递给客户端&#xff0c;而服务端的私钥则一直留在服务端。 在 RSA 密钥协商算法中&#xff0c;客户端会…

佳能打印机E568扫描书和文件方法

官方网站; Canon : Inkjet 手册 : IJ Scan Utility : 启动IJ Scan Utility 打开打印机电源 扫描一个文件&#xff0c;翻页后盖好盖子。再点击扫描。 所有扫描结束之后点退出 点击保存

【无限列车1】SpringCloudAlibaba 与 SpringBoot后端架构的搭建

【无限列车1】SpringCloudAlibaba 与 SpringBoot后端架构的搭建 1、版本说明二、日志相关配置3、AOP 打印日志4、下载开源前端后台管理系统5、添加网关模块6、集成数据库和mp(1) 添加驱动和mp依赖(2) 数据库配置(3) 使用MybatisPlus 7、加密 yaml 文件中的内容(1) 依赖(2) 敏感…

02---webpack基础用法

01 entry打包的入口文件&#xff1a; 单入口entry是一个字符串:适用于单页面项目module.exports {entry:./src/index.js}多入口entry是一个对象module.exports {entry:{index:./src/index.js,app:./src/app.js}} 02 output打包的出口文件&#xff1a; 单入口配置module.ex…

基于SSM的网络视频播放器

目录 背景 技术简介 系统简介 界面预览 背景 互联网的迅猛发展彻底转变了全球各类组织的管理策略。自20世纪90年代起&#xff0c;中国政府和企业便开始探索利用网络系统进行信息管理。然而&#xff0c;早期的网络覆盖不广泛、用户接受度不高、相关法律法规不完善以及技术开…

C#实现只保存2天的日志文件

文章目录 业务需求代码运行效果 欢迎讨论&#xff01; 业务需求 在生产环境中&#xff0c;控制台窗口不便展示出来。 为了在生产环境中&#xff0c;完整记录控制台应用的输出&#xff0c;选择将其输出到文件中。 但是&#xff0c;存储所有输出的话会占用很多空间&#xff0c;…

uniApp使用uview对vuex的二次封装实现全局变量

1、uni-app目根目录新建’/store/index.js’&#xff0c;并复制如下内容到其中 2、uni-app目根目录新建’/store/ u . m i x i n . j s ′ &#xff0c;并复制如下内容到其中&#xff0c;由于 H X 某些版本的限制&#xff0c;我们无法帮您自动引入 " u.mixin.js&#xff0…

element-ui card 组件源码分享

今日简单分享 card 组件源码&#xff0c;主要从以下两个方面&#xff1a; 一、card 组件页面结构 二、card 组件属性 2.1 header 属性&#xff0c;设置 header&#xff0c;也可以通过 slot#header 传入 DOM&#xff0c;类型 string&#xff0c;无默认值。 组件使用部分&#…

Linux TUN设备实现Tunnel性能分析

一、TUN/TAP设备原理&#xff1a; Linux的TUN/TAP设备是一种可以使得应用层与TCP/IP协议栈交互的驱动模块&#xff0c;通常用于组建虚拟局域网中的点对点隧道&#xff08;Tunnel&#xff09;&#xff0c;可以工作于2层&#xff08;TAP设备&#xff09;和3层&#xff08;TUN设备…

Linux的软链接和硬链接

1、软链接 概念&#xff1a;给文件创建一个快捷方式&#xff0c;依赖原文件&#xff0c;和普通文件没有区别。 特性&#xff1a; 可以给存在的文件或目录创建软链接可以给不存在的文件或目录创建软链接可以跨文件系统创建软链接删除软链接不影响原文件、删除原文件会导致软链…

moment.js 产出未知格式的时间,可能的原因

moment.js 产出未知格式的时间&#xff0c;可能的原因 有个问题困扰我好久了&#xff0c;在项目中使用格式化时间的时候会产出一些千奇百怪的格式&#xff0c;产出的文字我都不认识。 百思不得其解&#xff0c;终于今天在看代码的时候发现了这个问题。 它的表现是这样的&…

算法之模拟

前言 模拟算法通俗地来解释就是 "照葫芦画瓢", 通常这类题的题目中就说明了这道题应该怎么做, 要做的就是把题目的意思转化为代码, 这类题的特点是思路比较简单, 考查的是代码能力. 1. 模拟算法流程, 最好在演草纸上过一遍流程, 凭空想象可能会忽略一些细节 2. 把流…

软件架构复用

1.软件架构复用的定义及分类 软件产品线是指一组软件密集型系统&#xff0c;它们共享一个公共的、可管理的特性集&#xff0c;满足某个特定市场或任务的具体需要&#xff0c;是以规定的方式用公共的核心资产集成开发出来的。即围绕核心资产库进行管理、复用、集成新的系统。核心…

比较靠谱的测试进度报告

在测试的过程中&#xff0c;不要等领导过问&#xff0c;有一份比较靠谱的测试进度报告&#xff0c;让关心和支持项目的干系人心里有谱&#xff0c;有利于管理层对项目的监控和资源的支持&#xff0c;有利于项目团队成员之间沟通协调&#xff0c;及时发现问题利于项目风险控制等…

OpenHarmony实战:CMake方式组织编译的库移植

以double-conversion库为例&#xff0c;其移植过程如下文所示。 源码获取 从仓库获取double-conversion源码&#xff0c;其目录结构如下表&#xff1a; 表1 源码目录结构 名称描述double-conversion/cmake/CMake组织编译使用到的模板double-conversion/double-conversion/源…