Linux--文件

ok,我们今天了解一下Linux中的文件

理解“文件”

狭义理解

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

广义理解

  • Linux下⼀切皆⽂件(键盘、显⽰器、⽹卡、磁盘……这些都是抽象化的过程)

文件操作的归类认知

  • 对于0KB的空⽂件是占⽤磁盘空间的
  • 文件=内容 + 属性
  • 文件是⽂件属性(元数据)和⽂件内容的集合(⽂件=属性(元数据)+内容)
  • 所有的⽂件操作本质是⽂件内容操作和⽂件属性操作

系统角度

  • 对⽂件的操作本质是进程对⽂件的操作 
  • 磁盘的管理者是操作系统
  • ⽂件的读写本质不是通过C语⾔/C++的库函数来操作的(这些库函数只是为⽤⼾提供⽅便),⽽ 是通过⽂件相关的系统调⽤接⼝来实现的

访问文件前,都必须先打开它 ,没有被打开之前,文件是在磁盘上面。

访问文件是谁在访问/打开?是进程在访问文件而不是程序。

根据冯诺依曼体系,CPU无法直接访问磁盘,文件必须加载到内存中!

也就是说,访问文件,就是将文件加载到内存中。

一个进程可以打开多个文件,多个进程也可以打开一个文件。

OS必须要管理加载到内存中的文件。

如何管理文件?先描述再组织

文件的内核结构 + 文件的内容

C文件接口

hello.c打开⽂件

 #include <stdio.h>int main(){FILE *fp = fopen("myfile", "w");if(!fp){printf("fopen error!\n");}while(1);fclose(fp);return 0;
}

打开的myfile⽂件在哪个路径下?

在程序的当前路径下,那系统怎么知道程序的当前路径在哪⾥呢?

可以使⽤  ls / proc /  [ 进程 id] -l  命令查看当前正在运⾏进程的信息:

[hyb@VM-8-12-centos io]$ ps ajx | grep myProc 
506729  533463  533463  506729 pts/249   533463 R+     1002   7:45 ./myProc
536281  536542  536541  536281 pts/250   536541 R+     1002   0:00 grep --color=auto myProc[hyb@VM-8-12-centos io]$ ls /proc/533463 -ltotal 0......
-r--r--r-- 1 hyb hyb 0 Aug 26 17:01 cpusetlrwxrwxrwx 1 hyb hyb 0 Aug 26 16:53 cwd -> /home/hyb/io 
-r-------- 1 hyb hyb 0 Aug 26 17:01 environlrwxrwxrwx 1 hyb hyb 0 Aug 26 16:53 exe -> /home/hyb/io/myProcdr-x------ 2 hyb hyb 0 Aug 26 16:54 fd......
  • cwd:指向当前进程运⾏⽬录的⼀个符号链接。
  • exe:指向启动当前进程的可执⾏⽂件(完整路径)的符号链接

打开⽂件,本质是进程打开,所以,进程知道⾃⼰在哪⾥,即便⽂件不带路径,进程也知道。由此OS 就能知道要创建的⽂件放在哪⾥。

hello.c写⽂件

 #include <stdio.h>#include <string.h>int main(){FILE *fp = fopen("myfile", "w");if(!fp){printf("fopen error!\n");}const char *msg = "hello bit!\n";int count = 5;while(count--){fwrite(msg, strlen(msg), 1, fp);}fclose(fp);return 0;}

hello.c读⽂件

 #include <stdio.h>#include <string.h>int main(){FILE *fp = fopen("myfile", "r");if(!fp){printf("fopen error!\n");return 1;}char buf[1024];const char *msg = "hello bit!\n";while(1){//注意返回值和参数,此处有坑,仔细查看man⼿册关于该函数的说明ssize_t s = fread(buf, 1, strlen(msg), fp);if(s > 0){buf[s] = 0;printf("%s", buf);}if(feof(fp)){break;}}fclose(fp);return 0;}

稍作修改,实现简单cat命令:

 #include <stdio.h>#include <string.h>int main(int argc, char* argv[]){if (argc != 2) {printf("argv error!\n");return 1;}FILE *fp = fopen(argv[1], "r");if(!fp){printf("fopen error!\n");return 2;}char buf[1024];while(1){int s = fread(buf, 1, sizeof(buf), fp);if(s > 0){buf[s] = 0;printf("%s", buf);}if(feof(fp)){break;}fclose(fp);return 0;}

输出信息到显示器

 #include <stdio.h>#include <string.h>int main(){const char *msg = "hello fwrite\n";fwrite(msg, strlen(msg), 1, stdout);printf("hello printf\n");fprintf(stdout, "hello fprintf\n");return 0;
}

stdin & stdout &stderr

  • C默认会打开三个输⼊输出流,分别是stdin,stdout,stderr
  • 仔细观察发现,这三个流的类型都是FILE*,fopen返回值类型,⽂件指针
#include <stdio.h>extern FILE *stdin;extern FILE *stdout;extern FILE *stderr;

打开文件的操作

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

w 如果原文件有内容,会将原文件清空(截流在0字符位置)

a 以追加的形式打开文件,再写入的话直接追加在尾部

如上,是⽂件相关操作。还有  fseek  ftell  rewind 的函数

系统文件 I/O

打开文件的⽅式不仅仅是fopen,ifstream等流式,语⾔层的⽅案,其实系统才是打开⽂件最底层的方案。不过,在学习系统⽂件IO之前,先要了解下如何给函数传递标志位,该⽅法在系统⽂件IO接口中会使用到:

一种传递标志位的方法

#include <stdio.h>
#define ONE    0001 //0000 0001
#define TWO    0002 //0000 0010
#define THREE  0004 //0000 0100void func(int flags) {if (flags & ONE) printf("flags has ONE! ");if (flags & TWO) printf("flags has TWO! ");if (flags & THREE) printf("flags has THREE! ");printf("\n");
}int main() {func(ONE);func(THREE);func(ONE | TWO);func(ONE | THREE | TWO);return 0;
}

操作⽂件,除了上⼩节的C接⼝(当然,C++也有接⼝,其他语⾔也有),我们还可以采⽤系统接⼝ 进⾏⽂件访问,先来直接以系统代码的形式,实现和上⾯⼀模⼀样的代码:

hello.c 写⽂件:

#include <stdio.h>#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>#include <unistd.h>#include <string.h>int main(){umask(0);//更新默认权限int fd = open("myfile", O_WRONLY|O_CREAT, 0644);if(fd < 0){perror("open");return 1;}int count = 5;const char *msg = "hello bit!\n";int len = strlen(msg);while(count--){write(fd, msg, len);//fd: 后⾯讲,msg:缓冲区⾸地址, len: 本次读取,期望写⼊多少个字节的数据。返回值:实际写了多少字节数据}close(fd);return 0;}

hello.c读⽂件

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>int main(){int fd = open("myfile", O_RDONLY);if(fd < 0){perror("open");return 1;}const char *msg = "hello bit!\n";char buf[1024];while(1){ssize_t s = read(fd, buf, strlen(msg));//类⽐write if(s > 0){printf("%s", buf);}else{break;}}close(fd);return 0;}

接口介绍

open man open

 #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_t理解:直接man手册,比什么都清楚

open函数具体使用哪个,和具体应用场景相关,如目标文件不存在,需要open创建,则第三个参数白哦是创建文件的默认权限,否则,只用两个参数的open。

write read close lseek ,类比C文件相关接口

open函数返回值

系统调用和库函数

  • 上⾯的 fopen fclose fread  fwrite 都是C标准库当中的函数,我们称之为库函数 (libc)。
  •  open close read write lseek 都属于系统提供的接⼝,称之为系统调⽤接⼝
  •  回忆⼀下我们讲操作系统概念时,画的⼀张图

系统调⽤接⼝和库函数的关系,⼀⽬了然。

所以,可以认为, f# 系列的函数,都是对系统调⽤的封装,⽅便⼆次开发。

⽂件描述符fd

通过对open函数的学习,我们知道了⽂件描述符就是⼀个⼩整数

fd 数组下标

0 &1&2

  • stdin   标准输入 键盘     0
  • stdout 标准输出 显示器 1
  • stderr 标准错误 显示器  2

进程默认会打开三个输入输出流g

  • Linux进程默认情况下会有3个缺省打开的⽂件描述符,分别是标准输⼊0,标准输出1,标准错误2.
  •  0,1,2对应的物理设备⼀般是:键盘,显⽰器,显⽰器

所以输⼊输出还可以采⽤如下⽅式:

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
int main(){char buf[1024];ssize_t s = read(0, buf, sizeof(buf));if(s > 0){buf[s] = 0;write(1, buf, strlen(buf));write(2, buf, strlen(buf));}return 0;}

⽽现在知道,⽂件描述符就是从0开始的⼩整数。当我们打开⽂件时,操作系统在内存中要创建相应的 数据结构来描述⽬标⽂件。于是就有了file结构体。表⽰⼀个已经打开的⽂件对象。⽽进程执⾏open系 统调⽤,所以必须让进程和⽂件关联起来。每个进程都有⼀个指针*files,指向⼀张表files_struct,该表 最重要的部分就是包含⼀个指针数组,每个元素都是⼀个指向打开⽂件的指针!所以,本质上,⽂件 描述符就是该数组的下标。所以,只要拿着⽂件描述符,就可以找到对应的⽂件。

对于以上原理结论我们可通过内核源码验证:

⾸先要找到 task_struct 结构体在内核中为位置,地址为: 1160.71.1.el7.x86_64/include/linux/ 本,可使⽤ /usr/src/kernels/3.10.0 sched.h (3.10.0-1160.71.1.el7.x86_64是内核版 uname -a ⾃⾏查看服务器配置,因为这个⽂件夹只有⼀个,所以也不⽤刻意去分辨, 内核版本其实也随意)

  • 要查看内容可直接⽤vscode在windows下打开内核源代码
  • 相关结构体所在位置

少年没有乌托邦,心向远方自明朗!

如果这个博客对你有帮助,给博主一个免费的点赞就是最大的帮助
欢迎各位点赞,收藏关注
如果有疑问或有不同见解,欢迎在评论区留言
后续会继续更新大连理工大学相关课程和有关Linux的内容和示例
点赞加关注,学习不迷路,好,本次的学习就到这里啦!!!

ok,我们下次再见!

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

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

相关文章

Linux-数据结构-哈夫曼树-哈希表-内核链表

一.哈夫曼树 哈夫曼树&#xff08;Huffman Tree&#xff09;是一种特殊的二叉树&#xff0c;其定义和原理如下&#xff1a; 【1】定义 哈夫曼树是一种带权路径长度最短的二叉树。给定一组权值&#xff0c;将这些权值作为叶子节点的权值构造一棵二叉树&#xff0c;若该树的带…

前端抽象化,打破框架枷锁:统一路由的设计

个人博客原文地址 此文章并不适合初级前端来看&#xff0c;它是抽象的架构设计&#xff0c;需要一定的TS基础和抽象思维&#xff0c;若带着思考的读完本文章相信会让你感到充实 当然你也可以复制&#xff0c;然后在自己项目中去实现它&#xff0c;然后用起来 只要你是在写前端…

Docker 搭建部署 仓库的搭建以及网络设置

安装docker 一、关闭防火墙和SELinux 1.1systemctl stop firewalld 1.2setenfoce 0 二、配置内核转发以及网桥过滤 2.1vi /etc/sysctl.d/k8s.conf [rootopeneuler system]# vi /etc/sysctl.d/k8s.conf net.bridge.bridge-nf-call-ip6tables 1 net.bridge.bridge-nf-call-ip…

OSPF五种报文分析(仅部分比较重要的)

OSPF五种报文分别是&#xff1a; hello报文&#xff0c;DBD数据库描述报文&#xff0c;LSR链路状态请求报文&#xff0c;LSU链路状态更新报文&#xff0c;LSACK链路状态确认包 以下是这五种报文的详细解读&#xff1a; 1. Hello报文 作用&#xff1a; 用于邻居的发现、建立和…

【测试开发】OKR 小程序端黑盒测试报告

【测试报告】OKR 小程序端 项目名称版本号测试负责人测试完成日期联系方式OKR 小程序端4.0马铭胜2025-03-2515362558972 1、项目背景 1.1 OKR 用户端 在如今这个快节奏的时代中&#xff0c;个人和组织的成长往往依赖于清晰、明确且意义深远的目标。然而&#xff0c;如何设定…

【C++】内存模型分析

在 C 语言中&#xff0c;程序运行时的内存通常被划分为以下几个区域&#xff1a; 代码区&#xff08;Text Segment&#xff09;常量区&#xff08;Constant Segment&#xff09;全局/静态区&#xff08;Data Segment&#xff0c;包含静态数据段和 BSS 段&#xff09;堆区&…

关于解决Ubuntu终端及系统字体大小的问题

在Ubuntu中调整终端和系统字体大小可以通过以下方法&#xff08;可能不仅仅只是这几种&#xff09;实现&#xff1a; 1. 调整系统字体大小 打开终端并输入以下命令&#xff0c;安装GNOME Tweaks&#xff0c;等待安装完成&#xff1a; sudo apt install gnome-tweaks 接着进行…

java8循环解压zip文件---实现Excel文件数据追加

java8循环追加Excel数据 实际遇到问题&#xff1a;定期获取zip文件&#xff0c;zip文件内有几个固定模板的Excel文件&#xff0c;有的Excel文件可能还包含多个sheet。 有段时间一次性获取到好几个zip包&#xff0c;需要将这些包都解压&#xff0c;并且按照不同的文件名、sheet进…

内网渗透技术 Docker逃逸技术(提权)研究 CSMSF

目录 如何通过上传的webshell判断当前环境是否是物理环境还是Docker环境 方法一&#xff1a;检查文件系统 方法二&#xff1a;查看进程 方法三&#xff1a;检查网络配置 方法四&#xff1a;检查环境变量 方法五&#xff1a;检查挂载点 总结 2. 如果是Docker环境&#x…

MTK平台 Android12-Android13 默认搜狗输入法

系统默认搜狗输入法功能实现 文章目录 需求&#xff1a;场景 参考资料需求实现内置搜狗输入法配置第三方apk .mk 和 搜狗安装包&#xff0c;不可卸载方式搜狗输入法module 配置到系统device.mk 中去 设置搜狗输入法为默认输入法给输入法授权&#xff0c;默认所有权限 总结思考 …

一周掌握Flutter开发--8. 调试与性能优化(上)

文章目录 8. 调试与性能优化核心技能8.1 使用 Flutter DevTools 分析性能8.2 检查 Widget 重绘&#xff08;debugPaintSizeEnabled&#xff09;8.3 解决 ListView 卡顿&#xff08;ListView.builder itemExtent&#xff09; 其他性能优化技巧8.4 减少 build 方法的调用8.5 使用…

【区块链安全 | 第一篇】密码学原理

文章目录 1.哈希函数1.1 哈希函数的性质1.2 常见哈希算法1.3 Merkle Tree&#xff08;默克尔树&#xff09;1.4 HMAC&#xff08;哈希消息认证码&#xff09; 2. 公钥密码学2.1 对称加密 vs 非对称加密2.2 RSA 算法2.3 ECC&#xff08;椭圆曲线密码学&#xff09;2.4 Diffie-He…

vim的一般操作(分屏操作) 和 Makefile 和 gdb

目录 一. vim的基本概念 二. vim基础操作 2.1 插入模式 aio 2.2 [插入模式]切换至[正常模式] Esc 2.3[正常模式]切换至[末行模式] shift ; 2.4 替换模式 Shift R 2.5 视图&#xff08;可视&#xff09;模式 (可以快速 删除//注释 或者 增加//注释) ctrl v 三&…

NFC 智能门锁全栈解决方案:移动端、服务器、Web 管理平台

目录 一、系统整体架构 二、移动端 APP 开发 2.1 开发环境与基础准备 2.2 主要功能模块 2.3 示例代码&#xff08;Android/Kotlin 简化示例&#xff09; 三、后台服务开发 3.1 环境准备 3.2 主要功能 3.3 示例代码&#xff08;Node.js Express 简化示例&#xff09; …

系统与网络安全------网络应用基础(5)

资料整理于网络资料、书本资料、AI&#xff0c;仅供个人学习参考。 虚拟化 虚拟化技术原理概述虚拟化虚拟化实现条件常见的虚拟化软件产品 VMware应用实战安装VMware Workstation创建新虚拟机虚拟机的硬件配置调整 虚拟化高级应用虚拟机备份虚拟机快照 虚拟化技术 原理概述 虚…

Postman 下载文件指南:如何请求 Excel/PDF 文件?

在 Postman 中进行 Excel/PDF 文件的请求下载和导出&#xff0c;以下是简明的步骤&#xff0c;帮助你轻松完成任务。首先&#xff0c;我们将从新建接口开始&#xff0c;逐步引导你完成整个过程。 Postman 请求下载/导出 excel/pdf 文件教程

华为HCIE学习指南,如何更好的学习HCIE?

新盟教育 专注华为认证培训十余年 为你提供认证一线资讯&#xff01; 在竞争激烈的ICT行业&#xff0c;华为HCIE认证犹如一颗璀璨的明珠&#xff0c;散发着耀眼的光芒。它不仅是对个人技术能力的高度认可&#xff0c;更是开启高薪职业大门的钥匙。然而&#xff0c;华为HCIE学习…

贪心算法——c#

贪心算法通俗解释 贪心算法是一种"每一步都选择当前最优解"的算法策略。它不关心全局是否最优&#xff0c;而是通过局部最优的累积来逼近最终解。优点是简单高效&#xff0c;缺点是可能无法得到全局最优解。 一句话秒懂 自动售货机找零钱&#xff1a;用最少数量的…

架构思维:如何设计一个支持海量数据存储的高扩展性架构_数据分片、存储、复制与一致性的原理性问题

文章目录 PRE引言1. 数据分片策略Hash取模分片一致性Hash分片Range分片分片设计原理核心设计模块分片规则定义动态分片调整路由与负载均衡 应对热点的关键技术多级分片&#xff08;Hierarchical Sharding&#xff09;副本分散策略缓存层配合 典型应用场景优缺点分析 2. 应对热点…

Jenkins最新版,配置Gitee私人令牌和Gitee凭证

jenkins 配置Gitee私人令牌和凭证 jenkins 版本&#xff1a;Jenkins 2.492.2 Gitee配置 Jenkins配置gitee插件&#xff0c;需要先申请gitee私钥。 安装gitee插件 申请Gitee私人令牌&#xff0c;后面还需要添加凭证。 测试链接&#xff0c;并保存 配置凭证