• 操作系统:文件系统


    在这里插入图片描述

    文件在块设备上存储时,磁盘大致被分为三部分:

    1. 超级区
      负责"块设备"空间的分配和回收,记录块设备空间哪里用了哪里没用。

    2. inode节点区

      • 被划分为了一个个相连的,空间大小相同的inode节点空间。
      • 每个节点空间被用于存放某个文件的属性信息,每个节点空间大小是固定的比如一般的是512字节
      • 每个节点都有一个节点编号,通过节点编号就可以索引找到inode节点空间。
        使用stat读取文件属性时,struct stat结构体中的st_dev成员,就是用来存储inode节点编号的。
    3. 数据区
      数据区专门用于存放文件的数据。

      存储数据时,实际上并不是数据有多少个字节,就分配对应多少的字节空间给你,为了便于助理空间高效管理,往往都是按块分配空间的,一块往往为4k字节(4*1024) 。
      文件中的数据小于一块时,还是给你分配一块,当数据超过一块时,会给你再分配一块,当这一块又满了时,再给你分配一块。

      不同的数据块之间不一定是连续的,块之间使用地址进行相互链接,也即是说每一块都有存放前后块的地址,通过地址就可以找到前后块空间。

      • 目录文件
        目录文件的数据量小,所以一般就只有一块数据。目录文件里面放的内容,并不是目录所包含文件的数据,放的只是所包含文件的基本信息,其中两个信息最重要。文件名和文件的inode节点号
      • 链接文件
        存放的数据很简单,就是所指向文件的文件名。

    硬链接

    每创建一个硬链接,文件就多一个文件名,硬件链接数+1
    创建硬链接后所得到的多个文件名,指向的同一个inode节点,只有inode节点代表了文件的真实存在,inode节点只有一个,因此多个文件名指向的是同一个文件,不管使用的是哪一个文件名,都能操作这个文件。

    硬链接数

    记录了有多少个文件名指向这个inode节点,通过创建硬链接,每增加一个文件名,就多一个硬链接数。
    同理,每删除一个一个硬链接,也就是删除一个文件名,就少一个硬链接数,当然硬链接数被减为0时,也就代表着文件名被删除完了,这个文件也就被删除了。
    不过这里需要主要一点,当硬链接数被减为了0时,如果还有进程在操作这个文件的话,这个文件还会一直存在,直到进程结束后,这个文件才被删除。

    删除文件后,文件数据还在,因为删除文件时,只是将文件的inode节点空间释放了,如果这个文件的数据没有被覆盖的话,只要将文件的inode节点空间恢复,即可还原该文件。

    • 为什么新建的目录一开始的文件链接数就是2?
      因为新创建的目录,一开始就有两个名字指向了目录的inode节点,分别是目录的本名和.

    • 为什么在该目录下,每多创建一个目录,当前目录就会多一个硬链数?
      新创建目录的..名字,也指向了当前目录。

    • Linux不允许用户自己给目录创建硬链接,只能由Linux系统自己给目录创建硬链接。用户只能给目录以外的,其它类型的文件创建硬链接。

    link与unlink

    #include 
    int link(const char *oldpath,const char *newplath);//原有路径名->新路径名
    int unlink (const char *pathname) ;//pathname 删除硬链接的路径名
    
    • 1
    • 2
    • 3

    可以使用unlink创建临时文件,先用open创建一个文件,然后使用unlink删除文件的硬链接,在进程结束前还可以使用这个文件,进程结束后文件就删除了。

    remove

    #include 
    int remove (const char *pathname) ;
    
    • 1
    • 2

    功能:可以用于删除任何文件(既可以删除目录文件,也可以删除非目录文件)。删除非目录文件时,功能与unlink一样。

    remove是一个库函数。它封装了unlink和rmdir这两个系统函数。remove会自动检测文件类型,如果是目录就调用rmdir删除,如果其它文件,就调用unlink删除。

    rename

    #include 
    int rename(const char *oldpath,const char *newpath);
    
    • 1
    • 2

    功能:修改文件路径名,将旧的路径名oldpath,改为新的路径名newpath。

    mv就是调用rename函数实现的,看起来功能有三个(改名、移动、移动+改名),其实功能就一个,修改文件的路径名。

    符号链接

    符号链接文件也被称为软链接文件。
    使用ln -s就可以创建符号链接文件。

    符号链接与硬链接的对比
    • 创建硬连接
      同一个文件有多个不同的名字,它们指向是同一个inode节点。
    • 创建符号链接文件
      符号链接文件与它所指向的文件,是两个完全不同的独立的文件,拥有自己独立的inode节点。符号链接文件的数据就是指向文件的文件名,文件大小就是名字的字符个数。
    • 不能给目录创建硬链接,但是可以给目录创建符号链接

    symlink

    #include 
    int symlink(const char *oldpath,const char *newpath);
    
    • 1
    • 2

    功能:为oldpath,创建符号连接文件newpath。
    使用ln创建硬链接时,调用的是link函数。
    使用ln -s创建符号链接时,调用的是symlink,sym就是符号的意思。

    readlink

    #include 
    ssize_t readlink(const char *path,char *buf,size_t bufsiz);
    
    • 1
    • 2
    • 功能:读符号链接文件的数据(指向文件的名字)。readlink命令,就是调用这个函数实现的。
    • 参数
      • const char *path:符号连接文件的路径名。
      • char *buf:存放名字的缓存。
      • size t bufsiz:缓存的大小
    • 返回值:调用成功,返回读到的字节数,失败返回-1,errno被设置

    目录操作函数

    getcwd

    include <unistd.h>
    char *getcwd(char *buf, size_t size) ;
    char *getwd(char *buf); 
    
    • 1
    • 2
    • 3
    • 功能:获取进程的当前工作目录
    • 参数
      • buf:存放获取到的当前路径的缓存
      • size:缓存的大小
    • 返回值:成功返回指向字符串的指针,字符串存放当前工作目录,失败返回NULL,erno被设置。

    chdir

    #include 
    int chdir(const char *path);
    int fchdir(int fd) ;
    
    • 1
    • 2
    • 3

    切换进程当前工作目录到path或文件描述符fd指向的路径

    mkdir

    #include 
    #include 
    int mkdir(const char *pathname,mode_t mode);
    
    • 1
    • 2
    • 3
    • 功能:创建新目录。
    • 参数
      • pathname:需创建目录的路径名
      • mode:指定目录的原始权限,一般给0775
        给目录指定原始权限时,一定要有x权限,否者无法进入这个目录。
    • 返回值:调用成功返回0,失败返回-1,errno被设置

    rmdir

    #include 
    int rmdir(const char *pathname) ;
    
    • 1
    • 2
    • 函数功能:删除路径名为pathname的这个目录,必须是空目录,如果目录不空,则需递归删除。
      不管是我们讲那个函数,在指定路径名时,可以是相对路径,也可以是绝对路径。
      删除时,Linux系统会调用相关函数,将目录硬链数全部减位0,然后目录就被删除了。
    • 函数返回值:调用成功返回0,失败返回-1,errno被设置

    opendir

    #include                                                                
    #include                                                                  
    DIR *opendir(const char *name);                                                     
    DIR *fdopendir(int fd);
    
    • 1
    • 2
    • 3
    • 4
    • 功能:打开目录,不能使用open函数打开目录,只能使用opendir打开。

    • 参数:

      name:需打开目录的路径名
      fd:文件描述符

    • 返回值
      调用成功:返回一个DIR *的指针,这个指针指向了被打开的目录,readir通过这个指针就可以读取目录的目录项。
      调用失败:返回NULL,errno被设置。

    readdir

    #include 
    struct dirent *readdir(DIR *dirp) ;
    
    • 1
    • 2
    • 功能:读取目录里的目录项。每调用一次,就读取出一条目录项。

    • 参数
      dirp: opendir打开目录时,得到的指针。

    • 返回值:调用成功,返回指针指向struct dirent结构体的指针。这个结构体其实是定义在了头文件中。

      这个结构体就是用来存放一条目录项的,调用readdir读取到目录项后,会自动开辟一个struct dirent变量来存放目录项,然后将变量的指针返回,应用程序通过这个指针,就可以访问结构体中的目录项信息(文件基本信息)。

      struct dirent
      {
      	ino_t d_ino;/*i节点编号*/
      	off_t d_off;/*地址偏移*/
      	unsigned short d_reclen;/*本条目录项的大小*/
      	unsigned chard_type;/*文件类型,不是所有系统都支持*/
      	char d_name [256]; /*文件名字*/
      };
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8

      返回NULL的话有如下两种情况:
      1)读到目录的末尾时,返回NULL。
      2)函数调用失败时,也返回NULL,不过errno被设置。
      怎么判断函数是否调用失败了呢,如果ernno==0,表示没有设置错误号,返回NULL是因为读到了文件的末尾。如果errno!=0,表示是因为函数调用出错而返回的NULL。

    int main(void){
    	DIR *dirp = NULL;
        dirp = opendir(".");
        if(NULL == dirp)
        {
    		perror("opendir fail");
            exit(-1);
    	}
        while(1){
            struct dirent *direntp = NULL;
            direntp = readdir(dirp);
            if(direntp == NULL && errno!=0)//调用失败
            {
            	perror( "readdir fail");
                exit(-i);
            }
            printf("inodeID=%d,fnane=%s\n",direntp->d_ino,direntp->d_name);
            if(direntp == NULL && errno == 0) break;//读到目录末尾
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    chmod

    #include                                                                
    int chmod(const char *pathname, mode_t mode);                                    
    int fchmod(int fd, mode_t mode);     
    
    • 1
    • 2
    • 3
    • 功能:修改文件权限,比如将权限指定为0664等。
      chmod命令就是调用这两个函数来实现的。
      chmod:使用路径名操作
      fchmod:使用文件描述符操作
  • 相关阅读:
    Jmeter二次开发实现rsa加密
    mac电脑任务管理器 Things3 for Mac中文
    深度学习人体跌倒检测 -yolo 机器视觉 opencv python 计算机竞赛
    Spring 使用 Mypy 检查 30 万行代码,总结出三大痛点与六个技巧
    2023年Q4软件测试一般性趋势
    近两年国内外主流物联网操作系统简介
    Linux 之 vim
    品达通用_12. pd-tools-core+13. pd-tools-common+14. pd-tools-databases
    面试官:你说说 MySQL 索引失效有哪些场景?
    【数据结构趣味多】时间复杂度和空间复杂度
  • 原文地址:https://blog.csdn.net/wsl_longwudi/article/details/127445913