Linux基础IO

基础IO

​ 文件=文件的属性+文件的内容

​ 文件在Linux中可以分为打开的文件和没打开的文件;Linux将打开的文件载入内存并进行了管理,没打开的文件常见是存放在磁盘中。

一、打开的文件

1.c语言打开文件

​ c语言库函数封装了系统调用提供了管理在内存中文件的一套接口;

​ c语言默认会打开三个文件流stdin(对应键盘文件)、stdout(对应显示器文件)、stderr(对应显示器文件);

2.文件系统的系统调用

在这里插入图片描述

int open(const char *pathname, int flags, mode_t mode);
#pathname表示路径+将被打开的文件名,flags表示打开方式使用位图的方式来进行多模式选择,常用的方式有O_RRDONLY(只读方式),O_WRONLY(只写方式),O_RDWR(读写方式),O_CREAT(创建方式),O_APPEND(追加方式),O_TRUNC(覆盖方式);对于打开未创建的文件,会权限乱码,所以需要使用第三个参数,进行文件的权限设置,强行修改文件的权限;
#如:int fd = open("log.txt",O_WRONLY|O_CREAT|O_TRUNC,0666)
#返回值是文件描述符
int close(int fd)
#根据文件描述符关闭文件

在这里插入图片描述

#根据文件描述符将语言层缓冲区内容刷新到文件页缓冲区,进程结束会将文件内容刷新到磁盘;

3.打开文件内核结构

​ 操作系统会为每一个打开的文件建立一个struct file的结构体对象,管理多个被打开的文件;由于文件是被进程打开的所以进程的task_struct结构体中会存放一个struct files_struct* 的结构体指针,files_struct结构里存放了struct file类型的指针数组fd_array,数组下标就是文件描述符,每一个指针指向文件结构体对象;通过files_struct结构的方式实现了进程和文件管理的解耦合;默认0、1、2位置分别是键盘文件、显示器文件、显示器文件,1和2区别就是,1是正常输出文件,2是错误输出文件;

4.文件描述符和FILE*的关系

​ FILE结构封装了文件描述符,语言层缓冲区,可以实现对打开文件的管理;

5.重定向

5.1文件描述符的对应分配规则

​ 从0下标开始,寻找最小的没有被使用的数组位置,此位置下标就是新文件的文件描述符;

5.2重定向系统调用
int dup2(int oldfd, int newfd);
#将old位置打开文件的file指针拷贝到newfd位置
5.3重定向和进程程序替换

​ 要注意的是重定向不会影响进程程序替换,重定向修改的是files_struct这个进程和文件管理联系的结构,而进程程序替换修改的是mm_struct和页表这两个进程和内存管理联系的结构,本身并不会对进程模块、文件模块、内存模块产生影响;

5.4指令方式的重定向
> >> <
#>输出重定向,>>追加重定向;可以>文件名的方式,创建文件;<输入重定向;echo,print默认将字符串输入到显示器中,而cat默认从键盘中读取
./mytest 1>all.txt 2>&1
#实现错误信息和日志信息全部打印到一个文本文件中;

6.一切皆文件

​ Linux下一切都是以文件为主设计的,包括软件硬件各种资源,它们都继承了虚拟文件系统这个基类,继承了属性、读写方法和文件页缓冲区,对于软件和硬件又各自加入了自己的属性,并重写了方法。

7.缓冲区

​ Linux中又语言层缓冲区和系统缓冲区

​ Linux中语言层缓冲区刷新分为三种:1.无缓冲,直接刷新;2.行缓冲,遇到\n刷新;3.全缓冲,缓冲区满了才刷新;显示器文件根据人的阅读习惯使用的是行刷新,其他文件使用的是全刷新,都是为了提高效率;

​ c语言的写接口会将内容刷新到语言层缓冲区,并且接口里封装了write系统调用,在关闭文件时,会将调用write将数据刷新到文件页缓冲区。write系统调用接口会直接将数据刷新到文件页缓冲区,进程结束会将数据刷到磁盘;fflush(文件流)可以将数据立即刷新到文件页缓冲区;

​ 缓冲区的作用就是:1.提高效率;2.配和进行格式化;

​ FILE结构里封装了语言层缓冲区in和out;

二、未打开的文件

​ 一般是在磁盘中进行存储;包括内容(存放在数据块)和属性(使用inode128字节);

1.磁盘

1.1磁盘注意点

​ 1.磁盘是冯诺依曼体系中唯一一个机械运动的设备;本来外设的速度就很慢,机械运动就更加慢了;

​ 2.磁头惯性运动会导致刮花盘面,导致数据丢失;

​ 3.必须保证处于无尘环境,方式灰尘磨损盘面;

​ 4.删除磁盘的数据要通过加热消磁实现;

1.2磁盘构成

​ 主要有磁头,柱面(不同面的同半径磁道构成柱面),扇区构成;

​ 中间的马达向外有许多的同心圆,同心圆之间构成了磁道,数据就存放在扇形磁道上;磁盘被访问的最基本单元是扇区,一般是512b/4kb,所以就要实现快速定位扇区便于访问获取数据;考虑到效率的问题,应该将相关数据放在同一块区域;

1.3磁盘逻辑抽象

​ 将磁道延展开来逻辑上是由一个个512b大小的连续空间组成,是线性空间;一般是3个盘,6个盘面,每个面都可以抽象成线性空间;

​ 可以通过CHS(磁头、柱面、扇区)寻址方式访问物理空间;也可以使用LBA(逻辑抽象地址)以连续空间的方式访问;

​ 磁盘也有寄存器:控制寄存器、数据寄存器、状态寄存器、地址寄存器;操作系统通过检查状态寄存器决定是否将深度睡眠的进程唤醒;

2.ext2文件系统

​ 磁盘分区使用结构体partion对象,内部存放start和end指针来进行磁盘区域的划分;

在这里插入图片描述

​ Boot Block:启动块,记录了操作系统的启动相关信息,每一个分区都有启动块,损坏了可以使用其他分区的启动块拷贝修复,防止操作系统挂起;

​ Block group 0:组名,操作系统除了进行分区还进行了分组,每一个分组又包含了上述结构;

​ SuperBlock:描述整个分区信息和整个分区的使用情况,并不是每个分组都有;

​ Group Descriptor Table:描述分区分组情况和分组使用情况;

​ Block Bitmap:记录Data blocks的使用情况,使用0/1标识未使用/使用;

​ inode Bitmap:记录inode的使用情况,使用0/1标识未使用/使用;

​ inode Table:用来存放inode指针,一般一个文件对应一个inode,因为是连续空间所以天然有编号并且与多个数据块建立了联系;编号的分配方式和文件描述符类似;

​ Data blocks:存放文件内容,常见是4kb大小,因为是连续空间所以天然有编号;

​ 磁盘里专门为未打开文件建立了inode结构体,内部有inode编号、文件类型、权限、引用计数、拥有者、所属组、acm时间,还有数据块编号数组,大小为15,0-11直接索引,12-13二级索引,14三级索引;

mke2fs -b n
#修改块大小为n;
2.1目录文件

​ 目录文件有自己的inode和文件内容,内容是多个文件的文件名和inode映射,所以统一目录下不存在同名文件,要保证k唯一;没有可执行权限就无法拼接PWD环境变量,无法进入目录内;

三、软硬链接

ln -s 绝对路径 软连接文件名
#建立软链接,软连接是一个独立的文件,保存的是指向文件的路径
ln 文件名 硬连接文件名
#建立硬链接,硬链接本质上就是在当前目录下新建同一个inode的映射关系,使用引用计数,是没有独立的inode的;不允许对目录文件建立硬链接,防止环路访问问题;
ls -i
#显示文件inode;
unlink 文件名
#删除特殊文件

3.1硬链接的应用

​ .和…文件就是硬链接,可以帮助进行路径的快速切换,但是不可以自己对目录文件进行硬链接;

四、内存管理

​ 内存中的数据交换的最小单元叫做页框,大小为4kb,磁盘是页帧,大小为4kb,使用IO子系统将文件页缓冲区的数据刷新到磁盘;

​ 操作系统进行内存管理,用struct page结构进行描述,大小是4kb,也是用start和end指针来划分,总共可创建4gb/4kb个结构体,用mem_array数组存放page指针来管理,下标就是页号;对于大内存分配使用大伙伴系统算法,小内存分配使用slab分派器;

​ 在内存中会创建struct file结构、struct inode结构(会将磁盘中的inode属性拷贝)、struct address_space结构包含基数树(字母树)结构,树的叶节点存放page指针),file结构存放着inode指针和address_space指针,分别用来查找文件的属性和内容;文件管理和内存管理是通过inode和address_space结构来进行解耦合的;

五、动静态库

5.1制作动静态库

​ 静态库libxxx.a使用的方式是静态链接,将代码进行拷贝,动态库libxxx.so使用的方式是动态链接,将函数的地址拷贝;库封装就是打包.o文件;

​ 对于第三方编译程序,必须有头文件。有两种选择:1.头文件加源文件自己实现;2.头文件加库文件;

1.静态库

#制作静态库
lib = mylibmath.a
$(lib):mymath.o
	ar -rc $@ $^;#ar打包静态库命令,r表示代替,c表示创建
mymath.o:mymath.c
	gcc -c $^ -std=c99
.PHONY:clean
clean:
	rm -f *o *.a -r lib
#发布静态库
output:
	mkdir -p lib/include
    mkdir -p lib/mymathlib
    cp *h lib/include
    cp *.a lib/mymathlib

2.使用静态库

​ 第三方库的使用必须加选项 -l,errno是c标准库提供的一个全局变量;默认使用动态链接,但是如果没有动态库,只会使用静态链接的方式进行链接,加-static选项只能进行静态链接,不会查找动态库;

#注意#include<>/""是优先在系统默认头文件所在位置/user/include去查找,然后当前目录查找
gcc -o main.c -I lib/include -L lib/mymathlib -lmymath
#-I(include)表示去除了系统路径,当前目录之外的指定路径查找,-L(lib)指定路径查找库文件,-l(link)表示链接哪一个库,库的名字是去掉前缀和后缀,多个第三方库 -lpthread -l mymath
#由于每次编译都要加-I和-L选项过于麻烦,所以1.可以将头文件和库文件安装到系统路径下,也可以安装软连接到系统目录下,如创建一个软连接

2.动态库

​ 1.生成.o文件时,要加-fPIC(产生与位置无关码)选项;

gcc -fPIC -c mylog.c
gcc -fPIC -c myprint.c

​ 2.生产动态库需要加-shared选项,不然生成的就是可执行程序;

gcc -shared mylog.o myprint.o -o atest

​ 3.动态库带可执行权限是因为要进行动态库的加载,即可执行权限依赖动态库,会跳转到动态库中执行,所以动态库需要加载;

static-lib = libmymath.a
shared-lib = libmymethod.so 
all:$(static-lib) $(shared-lib)

$(static-lib):mymath.o
	ar rc $@ $^
mymath.o:mymath.c
	gcc -c $^ -std=c99

$(shared-lib):myprint.o mylog.o
	gcc -shared -o $@ $^ -std=c99 
myprint.o:myprint.c
	gcc -c -fPIC $^ -std=c99 
mylog.o:mylog.c
	gcc -c -fPIC $^ -std=c99 

.PHONY:clean
clean:
	rm -f *.o *.a *.so -r mylib
.PHONY:output
output:
	mkdir -p mylib/include
	mkdir -p mylib/lib
	cp *.h mylib/include
	cp *.a mylib/lib
	cp *.so mylib/lib
#生成可执行程序,但是i没有动态库加载不可以运行,而编译器能自动找到可执行的路径就是/lib64和/usr/bin,所以需要让动态库能加载,就需要让编译器能够找到,即4种。1.安装到系统目录/lib64;2.安装软链接;3.设置环境变量LD_LIBRARY_PATH;4./etc/ld.so.conf.d目录下,写一个.conf为后缀的配置文件,此类文件中存放的是路径,一个文件对应一个路径,可以将路径存放到此配置文件中,然后ldconf指令,更新一下动态库配置;
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/home/dyh/11/test/mylib/lib/
#可以将此文件写到bash_profile文件中;
gcc -o $@ $^ -std=c99 -I mylib/include -L mylib/lib -lmymath -lmymethod

在这里插入图片描述

在这里插入图片描述

5.2动态库加载

​ 动态库加载只会加载一份,并被所有的进程共享;所以操作系统会将载入内存的动态库进行管理;内核级虚拟机,在操作系统内执行操作系统的代码,在Linux中叫做docker;

​ 动态库文件是需要加载的,可执行程序会跳转到库文件执行函数;所以动态库经过页表的映射加载到共享区;多个进程可以根据页表映射共享动态库,库里面的变量被多个进程写入是会发生写时拷贝;

  • 25
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值