资讯详情

Linux操作系统的基础IO

📅 2026/9/23 8:54:53 | 华诺云谱 👁 阅读
Linux操作系统的基础IO
目录系统文件IOopen函数0 1 2文件描述符的分配规则重定向输入重定向输出重定向追加重定向dup2FILE文件系统inode软硬链接软链接硬链接动态库和静态库动静态库的命名方式静态库制作一个库使用库动态库制作一个库使用库系统文件IOopen函数intopen(constchar*pathname,intflags);//文件存在选这个函数intopen(constchar*pathname,intflags,mode_t mode);//文件不存在选这个函数pathname:要打开或创建的目标文件名flags:打开文件时可以传入多个参数选项用下面的一个或者多个常量进行“或”运算构成flags。参数:O_RDONLY:只读打开O_WRONLY:只写打开O_RDWR :读写打开这三个常量必须指定一个且只能指定一个O_CREAT :若文件不存在则创建它。需要使用mode选项来指明新文件的访问权限比如0666O_APPEND:追加写O_TRUNC:每次打开对文件时清理返回值成功新打开的文件描述符失败-1mode_t理解直接 man 手册比什么都清楚。open 函数具体使用哪个和具体应用场景相关如目标文件不存在需要open创建则第三个参数表示创建文件的默认权限,否则使用两个参数的open。0 1 2Linux任何一个进程在启动的时候默认会3个文件分别是标准输入0 标准输出1 标准错误2.0,1,2对应的物理设备一般是键盘显示器显示器当进程调用open打开或创建一个文件时就在内存创建一个struct file的结构体结构体里面会包含有对应的文件的相关属性比如文件的类型文件的读写位置等在将创建的struct file结构体的地址在执行打开或创建文件的进程的struct tak_struct的结构体中找到结构体成员struct file_struct* file指向的地址中struct file* fd_array[]数组中从上到下找到一个空位置将将创建的struct file结构体的地址填到里面就建立了进程与文件的对应关系。struct file结构体以双链表的形式连接起来对链表的增删查改也就变成对文件的管理。当调用write函数时OS做了什么首先执行这个write函数的一定是你自己的进程在执行不是其他人进程在执行是你这个进程。当在数据写入时你其实是调了write函数然后操作系统识别到系统要用然后OS就帮你去写入了。他在写入时首先要做的工作找到你这个进程的PCB因为是文件操作所以他要找struct file_struct* file然后拿着你传进来的文件描述符在数组中找到struct file*所以就找到匹配的文件将用户层所对应的数据直接从应用层通过这种索引方式拷贝到对应的缓冲区当中。write或read函数本质,拷贝函数文件描述符的分配规则进程中文件描述符的分配规则在文件中描述符中最小的没有被使用的数组元素分配给新文件或打开的文件依次从上向下分配。重定向重定向的原理在上层无法感知的情况下在OS内部更改进程对应的文件描述表中特定下标的指向。输入重定向输出重定向追加重定向标准输出与标准错误的区别。因为输出重定向只改的是1标准输出描述符对应的指向2号标准错误文件描述不受影响。dup2intdup2(intoldfd,intnewfd);函数功能将newfd文件夹描述符中的内容重定向到oldfd文件描述中。FILE因为IO相关函数与系统调用接口对应并且库函数封装系统调用所以本质上访问文件都是通过fd访问的。所以C库当中的FILE结构体内部必定封装了fd我们用的编程语言都是在操作系统的上层用C语言时调printf调fprintf(这些函数都是对系统函数的封装open)那么这样的接口是你只是把数据从你自己写的代码当中交给了C标准库C标准库它内部会帮我们维护对应的缓冲区缓冲区维护好之后它会按照自己的一定的刷新测略将数据从你的FILE中的fd刷新到特定进程所对应的文件的缓冲区中然后在刷新到磁盘中。C库的刷新策略无缓冲是在进行写入操作时直接刷新到OS(操作系统)中。行缓冲当我们将数据写到缓冲区时只要碰到\n就将\n前的数据刷新的OS中。全缓冲只有当缓冲区写满时才将数据刷新到OS中。显示器采用的是的刷新策略是行缓存普通文件采用的是的刷新策略是全缓冲为什么要有缓冲区节省调用者的时间系统调用也是要花费时间的。缓冲区在哪在你进行fopen打开文件时你会得到一个FILE的结构体缓冲区就在这个FILE结构体中。为什么出现这种现象首先write是系统调用接口它不属于C标准库调用直接写入到操作系统了。fprintf是C标准库函数它写入数据是先写入到C标准库的的缓冲区中然后在写入的操作系统中。一般C库函数写入文件时是全缓冲的而写入显示器是行缓冲。当写向显示器写入显示器是行缓冲fork之前,write fprintf已经刷新完了。当重定向到文件中printf fwrite库函数会自带缓冲区当发生重定向到普通文件时数据的缓冲方式变成了全缓冲。而我们放在缓冲区中的数据就不会被立即刷新甚至fork之后但是进程退出之后会统一刷新写入文件当中。但是fork的时候父子数据会发生写时拷贝所以当你父进程准备刷新的时候子进程也就有了同样的一份数据随即产生两份数据。write函数直接写入到操作系统中的文件内核缓存区(在struct file中)。文件系统文件根据有没被打开可分为打开的文件存在于内存又称为内存文件没打开的文件存在于磁盘又称为磁盘文件下面我们来谈谈磁盘文件。文件 内容 属性Linux操作系统的文件是将内容和属性分离的。inode文件储存在硬盘上硬盘的最小存储单位叫做”扇区”Sector。每个扇区储存512字节相当于0.5KB。操作系统读取硬盘的时候不会一个个扇区地读取这样效率太低而是一次性连续读取多个扇区即一次性读取一个”块”block。 这种由多个扇区组成的”块”是文件存取的最小单位。”块”的大小最常见的是4KB即连续八个 sector组成一个 block。文件数据都储存在”块”中那么很显然我们还必须找到一个地方储存文件的元信息比如文件的创建者、文件的创建日期、文件的大小等等。这种储存文件元信息的区域就叫做inode中文译名为”索引节点”。一个大小为0的文件文件系统也会为其维护一个inode。Linux ext2文件系统上图为磁盘文件系统图内核内存映像肯定有所不同磁盘是典型的块设备硬盘分区被划分为一个个的block。Boot Block启动块大小为1kb由pc标准规定的用来存储磁盘分区信息和启动信息任何文件系统都不能操作该块.Block Groupext2文件系统会根据分区的大小划分为数个Block Group。而每个Block Group都有着相同的结构组成.超级块(Super Biock) 文件系统的所有属性信息包括文件系统的类型,文件系统整个分组的情况Super Biock在各个分组里面可能都会存在而且是统一更新的是为了防止Super Biock区域坏掉。如果出现故障,整个分区不可以被使用所以做好备份保护数据安全。它是多副本保证分区安全的策略。Group Descriptor Table简称GDT组描述符描述组属性信息描述group内各个位置存储的信息如Block Bitmap的起始位置和length等等inode Table一个文件,内部所有属性的集合用inode节点(128字节)表示这个inode节点保存该文件所有属性。所有文件属性的大小都是128字节(文件名不会作为属性保存在文件的inode中所以才能保证所有的文件属性的大小都是128字节)。文件系统中是以块(4Kb)单位的一个块(4Kb)内保存32个inode也称文件属性(4096 / 128 32)。一个文件一个inode。一个分组内部也会存在大量的文件即会存在大量的inode节点。一个组区域来专门保存该group内的所有文件的inode节点的称为inode table也称为(inode表)。分组内部可能会存在多个inode,需要将inode区分开来, 每一个inode都会有自己的inode编号,inode编号也属于对应文件的属性id。Data Blocks我们是用数据块来进行文件内容的保存的所以一个有效文件要保存内容,就需要[1, n]数据块即使要保存的数据是一个字节也要开一数据块如果有多个文件呢?需要更多的数据块。可以将Data Blocks看做一个特别大的数组数组的每个元素的大小是4KB数据块所以Data Blocks就是存放所有分组文件中用到的所有数据块。Linux查找一 个文件,是要根据inode编号,来进行文件查找的包括读取内容! !都是根据inode编号找到inode节点就是结构体结构体内部会有一块地址存放Data Blocks数组的下标这些下标所对应的数据块就是个文件的内容。一个inode对应一 个文件该文件inode属性和该文件对应的数据块,是有映射关系的。inode Bitmap(inode位图)每个bit为表示node Table表中的一个inode是否空闲可用。Block Bitmap每个bit为表示Data Blocks数组中的下标是否空闲可用。[whdVM-8-16-centos 2023_10_9]$ls-iltotal321572945drwxrwxr-x2whd whd4096Oct2208:51 list1314304-rw-rw-r--1whd whd65Oct1815:29 makefile1314306-rwxrwxr-x1whd whd8496Oct2009:40 myfile1314302-rw-rw-r--1whd whd2387Oct2009:38 myfile.c1314303-rw-rw-r--1whd whd40Oct2009:40 test.c1314305-rw-rw-r--1whd whd260Oct1817:48 test.cc[whdVM-8-16-centos 2023_10_9]$Linux系统只认inode编号文件的inode属性中, 并不存在文件名。文件名是给用户用的。任何一个文件一定在一个目录内部目录也是inode 与 数据内容构成的目录的数据块里面保存的是该目录下文件名和文件inode编号对应的映射关系而且在目录内文件名和inode是KV关系。当我们访问一个文件的时候我们是在特定目录下访问的比如(cat test.c)先要在当前目录下找到test.c的inode编号。一个目录也是一个文件,也一定隶属于一个分区, 结合inode 在该分区中找到分组 在该分组中inode table中,找到文件的inode。通过inode和对应的data block的映射关系,找到改文件的数据块并加载到OS,并完成显示到显示器。Linux如何删除文件根据文件名找到inode number(inode编号)。inode number找到inode属性中存放的该文件使用Data Blocks数据块的编号根据编号将设置block bitmap对应的比特位置0即。删除内容。inode number设置inode bitmap对应的比特位设置为0。删除属性。所以删文件只需要需改位图即可。inode number是在一个分区内唯一有效的不能跨分区。有没有可能一个分组数据块没用完inode没了或者inode没用完data block用完了有可能因为inode Bitmap和Block Bitmap是固定大小的。但是没办法解决。软硬链接软链接ln -s myfile.txt my-soft后者链接前者。软连接类似于windows的快捷键是一个将路径很长的可执行程序链接到当前路径下以方便快速执行。软连接是一个独立的连接文件有自己的inode number, 必有自己的inode属性和内容。软连接的文件内部放的是自己所指向文件的路径。所以软链接的文件大小才不一样。硬链接ln myfile.txt my-hard后者链接前者。硬链接和目标文件公用同一个inode number,意味着硬链接一定是和目标文件使用同一个inode硬链接没有独立的inode。那硬链接究竟干了什么?建立了新的文件名与旧文件的inode的映射关系同时将新文件与旧文件映射的同一inode结构体inode结构体中硬链接数如果删除关联这个inode结构体的其中一个文件inode结构体中硬链接数–只有inode结构体中硬链接数为0时才是删除这个硬链接数本质上是引用计数。Linux中的. 当前目录 .. 上级目录就是靠硬链接的方式实现的。Linux不能给目录建立硬链接硬链接只能给文件建立Linux系统不支持用户给目录建立硬链接Linux系统只允许系统本身给目录建立硬链接比如 . )。因为容易造成环路问题比如find查找文件时。软链接文件的属性上加了 l 在查找时就会将软连接文件识别为普通文件就不会造成环路问题了。动态库和静态库静态库.a是指编译链接时,把库文件的代码全部复制加入到可执行文件中,因此生成的文件比较大,但在运行时也就不再需要库文件了。动态库.so程序在运行的时候才去链接动态库的代码一个与动态库链接的可执行文件仅仅包含它用到的函数入口地址的一个表而不是外部函数所在目标文件的整个机器码动态库可以在多个程序间共享所以动态链接使得可执行文件更小节省了磁盘空间。操作系统采用虚拟内存机制允许物理内存中的一份动态库被要用到该库的所有进程共用节省了内存和磁盘空间。动静态库的命名方式Linux动静库文件必须以lib开头 文件名 .(必须是第一个.后跟如果是动态库so,如果是静态库a)。头文件源文件目标文件gcc编译第三方库需要携带的三个选项-I:指定头文件的搜索路径-L:指定库文件的搜索路径-l:指定库文件的名称只要库名即可(去掉lib版本号以及后缀)静态库制作一个库制作一个库必须是经过预处理编译汇编的.o文件。ar-rclibXXXXX.a *.o //制作静态库ar命令是gun归档工具ar-tvlibxxxxx.a //查看静态库文件的详细信息t: 列出静态库中的文件v(verbose): 显示详细信息使用库gcc -o mytest main.c -I ./include -L ./lib -l mymath第三方库的使用。1.需要指定的头文件,和库文件2.如果没有默认安装到系统gcc、g 默认的搜索路径下,用户必须指明对应的选项告知编译器: a. 头文件在哪里b.库文件在哪里c.库文件具体是谁3.将我们下载下来的库和头文件拷贝到系统默认路径下----在Linux下安装库! ! 那么卸载呢? ?对任何软件而言安装和卸载的本质就是拷贝到系统特定的路径下4.如果我们安装的库是第三方的(语言第一方库操作系统系统接口第二方库)我们要正常使用即便是已经全部安装到了系统中gcc/g必须用-I指明具体库的名称动态库制作一个库制作一个库必须是经过预处理编译汇编的.o文件。生成动态库fPIC产生位置无关码(position independent code)gcc -fPIC -c (.c文件)shared: 表示生成共享库格式gcc -shared -o libxxxx.so (经过预处理编译汇编的.o文件)使用库这条指令gcc -o mytest main.c -I ./include -L ./lib -l mymath在编译期间告诉gcc编译器头文件的路径指定库的路径指定库的名称。要知道可执行程序是由操作系统运行的。在包含动态库的可执行程序在运行时要链接动态库。./mytest在运行时要链接动态库OS(操作系统)在规定的路径下找不到可执行的程序所依赖的动态库在哪里所以才运行出错。ldd mytest //查看可执行程序所依赖的动态库运行时OS是如何查找动态库呢更改LD_LIBRARY_PATH(临时方案)LD_LIBRARY_PATH是OS链接动态库时搜索的路径我们只需要将自己制作的动态库所在的目录追加到LD_LIBRARY_PATH环境变量中即可。注意这种方法只是临时的当你重新进入会话时这个环境变量还需要重新添加。export LD_LIBRARY_PATH$LD_LIBRARY_PATH:自己制作的动态库所在的路径拷贝.so动态库文件的系统的默认搜索路径下或建立软链接。建立软连接将自己制作的动态库链接到系统的默认搜索路径下/lib64sudo ln -s /home/whd/Code/linux/2023_10_22/otherPerson/lib/libmymath.so /lib64/libmymath.so配置/etc/ld.so.conf.d/ldconfig更新。/etc/ld.so.conf.d/目录中放的是动态链接库的配置文件。配置文件的命名可以自定义配置文件中放动态库的绝对路径。操作系统这三种方案其实它都是会查找处理的。为什么静态库就能找到?链接原则:将用户使用的二进制代码直接拷贝到目标可执行程序中! 但是动态库不会!注意动态库和静态库是没有main函数的。
📝

华诺云谱内容团队

资深建站顾问 · 行业研究员

10年+企业数字化服务经验,专注智能建站、SEO优化与品牌营销,持续输出建站技巧、行业洞察与营销干货,已帮助5000+企业实现数字化增长。

你可能需要的服务

订阅华诺云谱资讯周报

每周一封,精选建站技巧、SEO与营销干货,直达邮箱。已有 8,000+ 企业主订阅,助你少走弯路。