基于LINUX的文件系统、文件类型、文件的打开与关闭、文件的内核结构

基于LINUX的文件系统、文件类型、文件的打开与关闭、文件的内核结构文件系统 物理结构 每个磁盘由多个盘片构成 每张盘片由多个磁道构成 每个磁道按照 512 字节等分 每等份叫做扇区 越靠近外圈扇区越多 柱面 不同盘片相同半径的磁道所组成的圆柱称为柱面 整个磁盘的柱面与每张磁盘的磁道数相同 磁盘中的每个扇区由磁头号 柱面号 扇区号唯一确定

大家好,我是讯享网,很高兴认识大家。

文件系统:
物理结构:每个磁盘由多个盘片构成,每张盘片由多个磁道构成,每个磁道按照512字节等分,每等份叫做扇区,越靠近外圈扇区越多。
柱面:不同盘片相同半径的磁道所组成的圆柱称为柱面,整个磁盘的柱面与每张磁盘的磁道数相同。
磁盘中的每个扇区由磁头号、柱面号、扇区号唯一确定。


讯享网
数据块:存储文件内容
块位图:记录0和1,一个byte位对应一个数据块,记录数据块使用情况

i节点映射表:记录i节点编号和磁盘上存储对应位置,帮助找到i节点的位置。
磁盘中的每个文件或目录都有唯一的一个的i节点与之对应。
每个i节点都有唯一的编号即i节点号,通过i节点映射表可以查到与每个i节点号相对应的i节点在磁盘上的存储位置。


文件名和i节点的对应关系记录在该文件所在目录的目录文件中,目录文件中的一条这样的记录就是一个硬链接。
ls -i 命令可以查看文件的i节点号
每个节点号记录一个(普通)文件的元数据(属性信息),和数据块(内容数据)

例:uc/hello.h
uc:对应的i节点存储自己的属性和目录数据{下(hello.h和i节点对应关系)}
直接块:存储文件内容
间接块:存储文件与i节点对应关系

 文件类型:通过ls -l 命令可以查看文件的类型
-:普通文件   d:目录  s:本地套接字  c:字符设备  b:块设备  l:软链接 p:有名管道

文件的打开与关闭:

#include<stdio.h> #include<fcntl.h>//open #include<unistd.h>//close int main(void) { //打开文件 int fd = open("open.txt",O_RDWR | O_CREAT |O_TRUNC,0777); if(fd == -1) { perror("open"); return -1; } printf("fd=%d\n",fd); //关闭文件 close(fd); return 0; }

讯享网

文件的打开与关闭:
#include <fcntl.h>
int open(char const* pathname, int flags, mode_t mode);
功能:打开已有的文件或创建新文件
参数:pathname 文件路径
flags 状态标志,可以以下取值 
O_RDONLY- 只读 
O_WRONLY-只写 
O_RDWR -读写 
O_APPEND-追加
O_CREAT-不存在即创建,已存在即打开 
O_EXCL-不存在即创建,已存在即报错 
O_TRUNC-不存在即创建,已存在即清空

参数:mode 权限模式
仅在创建新文件时有效,可用形如0XXX的三位八进制数表示,由高位到低位依次
表示拥有者用户、同组用户和其它用户的读、写和执行权限,读权限用4表示,写权限用2表
示,执行权限用1表示,最后通过加法将不同的权限组合在一起
返回值:所返回的一定是当前未被使用的,最小文件描述符
调用进程的权限掩码会屏蔽掉创建文件时指定的权限位,如创建文件时指定权限0666
进程权限掩码0022,所创建文件的实际权限为:0666&~0022=0644 (rw-r--r--)

#include <unistd.h>
 int close(int fd);
功能:关闭处于打开状态的文件描述符
参数:fd 处于打开状态的文件描述符
 

文件的内核结构:

一个处于打开的文件,系统会为其在内核中维护一套专门的数据结构,保存该文件的信息,直到它被关闭。

v节点与v节点表:
文件的元数据和在磁盘上的存储位置都保存在其i节点中,而i节点保存在分区柱面组的i节点表中,在打开文件时将其i节点信息读入内存,并辅以其它的必要信息形成一个专门的数据结构,势必会提高对该文件的访问效率,这个存在干进程的内核空间,包含文件i节点信息的数据结松被称为v节点。多个v节点结构以链表的形式构成v节点表
 文件表项与文件表:
由文件状态标志(来自open函数的flags参数)、文件读写位置(最后一次读写的最后一个字节的下一个位置)和v节点指针等信息组成的内核数据结构被称为文件表项。通过文件表项一方面可以实时记录每次读写操作的准确位置,另一方面可以通过v节点指针访问包括该文件各种元数据和磁盘位置在内的i节点信息。多个文件表项以链表的形式构成文件表

*多次打开同一个文件,无论是在同一个进程中还是在不同的进程中,都只会在系统内核中产生一个v节点
*每次打开文件都会产生一个新的文件表项,各自维护各自的文件状态标志和当前文件偏移,却可能因为打开的是同一个文件而共享同一个v节点
*打开一个文件意味着内存资源(v节点、文件表项等)的分配,而关闭一个文件其实就是为了释放这些资源,但如果所关闭的文件在其它进程中正处于打开状态,那么其v节点并不会被释放,直到系统中所有曾打开过该文件的进程都显式或隐式地将其关闭,其v节点才会真正被释放
*一个处于打开状态的文件也可以被删除,但它所占用的磁盘空间直到它的v节点彻底消失以后才会被标记为自由

文件描述符:

 为了便于管理在系统中运行的各个进程,内核会维护一张存有各进程信息的列表,谓之进程表。系统中的每个进程在进程表中都占有一个表项。每个进程表项都包含了针对特定进程的描述信息,如进程ID、用户ID、组ID等,其中也包含了一个被称为文件描述符表的数据结构。
文件描述符表的每个表项都至少包含两个数据项--文件描述符标志和文件表项指针,而所谓文件描述符,其实就是文件描述符表项在文件描述符表中从0开始的下标。

 文件读写:

#include <unistd.h>
ssize_t write(int fd, void const* buf, size_t count)
功能:向指定的文件写入数据
参数:fd 文件描述符
buf 内存缓冲区,即要写入的数据
count 期望写入的字节数
返回值:成功返回实际写入的字节数,失败返回-1。

讯享网#include<stdio.h> #include<unistd.h> #include<string.h> #include<fcntl.h> int main(void) { //打开文件 int fd = open("./shared.txt",O_WRONLY | O_CREAT | O_TRUNC,0664); if(fd ==-1) { perror("open"); return -1; } printf("fd=%d\n",fd); char * buf = "hello,world!"; //写入文件 ssize_t size = write(fd,buf,strlen(buf)); if(size == -1) { perror("size"); return -1; } printf("实际写入%ld个字节\n",size); //关闭文件 close(fd); //------------------------------------------------------------------ int fd1 = open("./shared1.bin",O_WRONLY | O_CREAT | O_TRUNC,0664); if(fd1==-1) { perror("open"); return -1; } printf("fd=%d\n",fd1); ssize_t size1 = write(fd1,buf,strlen(buf)); if(size1 == -1) { perror("size1"); return -1; } printf("实际写入%ld个字节\n",size1); //关闭文件 close(fd1); return 0; }

#include <unistd.h>
ssize_t read(int fd, void* buf, size_t count);
功能:从指定的文件中读取数据
参数:fd 文件描述符
buf 内存缓冲区,存读取到的数据 
count 期望读取的字节数
返回值:成功返回实际读取的字节数,失败返回-1。
 

#include<stdio.h> #include<unistd.h> #include<fcntl.h> int main(void) { //打开文件 int fd = open("./shared.txt",O_RDONLY); if(fd ==-1) { perror("open"); return -1; } //读取文件 char buf[24]; ssize_t size = read(fd,buf,sizeof(buf)- sizeof(buf[0])); if(size ==-1) { perror("read"); return -1; } printf("size=%ld",size); printf("%s\n",buf); //关闭文件 close(fd); return 0; } 

文件读写位置:

#include <unistd.h>
off_t lseek(int fd, off_t offset, int whence);
功能:人为调整文件读写位置>参数:fd:文件描述符。
offset:文件读写位置偏移字节数
whence:offset参数的偏移起点,可以如下取值:
    SEEK SET-从文件头(首字节)开始
    SEEK CUR-从当前位置(最后被读写字节的下一个字节)开始 SEEK END-从文件尾(最后一个字节的下一个字节)开始
返回值:成功返回调整后的文件读写位置,失败返回-1
 

用lseek定位到当前文件尾端,在向文件写入(write)与使用O_APPEND(追加)打开(open)文件再写入(write)的区别:
前者是“非原子”操作,假如两个进程都使用前者的方式向文件结尾写入数据,那么有可能产生这样的调度序列:
进程A:leek  进程B:leek 进程A:write 进程B:write
第一个进程写入后,文件(i节点)的偏移已经改变,第二个进程再写会覆盖第一个进程刚写的内容。而是用O_APPEND的open,会使内核每次对文件写之前,都将进程的当前偏移量(file对象中的)设置到文件的尾端处(i节点的当前文件长度)。
注意:对于多个进程打开同一文件的情况,每个进程都有它自己的文件表项(file对象),其中有它自己的文件位移量,所以对于多个进程读同一文件都能正确工作。但是,当多个进程写同一文件时,则可能产生预期不到的结果。(可以使用pread,pwrite)。
总结:两个独立进程打开同一文件,对应不同的file对象,每个进程调用close只影响本进程的“打开文件计数”(file对象的引用计数)。

小讯
上一篇 2025-03-03 16:08
下一篇 2025-01-19 22:49

相关推荐

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/49339.html