Linux那点事-文件系统

作者: 小胖学编程 | 来源:发表于2019-03-30 21:21 被阅读264次

    1. Linux文件系统

    Windows操作系统中,使用驱动器盘符(比如C盘),决定文件的路径名。每个驱动器都会有自己的目录结构,以便访问文件。

    Linux的路径名不使用驱动器盘符。而是将文件存储在单个目录结构中,这个目录结构称为虚拟目录 virtual directory。虚拟目录将所有的文件目录纳入到单个目录结构中。

    Linux虚拟目录结构只包含了一个称为根(Root)目录的基础目录。

    注意:

    • Linux使用正斜线(/)而不是反斜线(\)在文件路径中划分目录。在Linux中,反斜线用来标识转义字符。

    • 无论是window环境还是Linux环境,我们关注的还是java获取路径的方法。

    Java获取文件路径:

     public static void main(String[] args) throws IOException {
            System.out.println("系统默认的分隔符:"+File.separator);
            File emptyFile = new File("");
            System.out.println("项目路径:"+System.getProperty("user.dir"));
            //返回抽象路径名的绝对路径字符串
            System.out.println("absolutePath路径为空时:"+emptyFile.getAbsolutePath());
            System.out.println("canonicalPath路径为空时:"+emptyFile.getCanonicalPath());
            System.out.println();
            //路径是.或者..时候
            File file1 = new File(".");
            System.out.println("absolutePath路径为.时:"+file1.getAbsolutePath());
            System.out.println("canonicalPath路径为.时:"+file1.getCanonicalPath());
            System.out.println();
            File file2 = new File("..");
            System.out.println("absolutePath路径为..时:"+file2.getAbsolutePath());
            System.out.println("canonicalPath路径为..时:"+file2.getCanonicalPath());
            //路径是绝对路径时
            System.out.println();
            File absoluteFile = new File("/");
            System.out.println("absolutePath路径为绝对路径时:"+absoluteFile.getAbsolutePath());
            System.out.println("canonicalPath路径为绝对路径时:"+absoluteFile.getCanonicalPath());
        }
    

    执行结果:

    获取路径的方法

    在Linux中,会看到下面这种路径:
    /home/Rich/Document/test.doc
    这表明文件test.doc位于Document目录, Document又位于Rich目录之下,Rich则是在home路径之下的。路劲本身并没有提供任何有关文件究竟存放在哪个物理磁盘的信息。

    1.2 Linux如何协调管理各个存储设备

    Linux不使用驱动盘符,而是将文件存储在单个目录结构中,这个目录结构称为虚拟目录。而Linux第一块硬盘。即根驱动器,包含了虚拟目录的核心,其他目录都是在这构建的,可以挂载一些存储设备,我们称之为挂载点

    Linux会在根驱动器创建一些特别的目录,我们称之为挂载点mount point),挂载点是虚拟目录中用于分配额外存储设备的目录虚拟目录会让文件目录出现在这些挂载点目录中,然而实际上他们却存储在另外一个存储器中。

    虚拟目录和挂载:

    1. 虚拟目录结构只包含一个称为根目录的基础目录。
    2. Linux第一块硬盘是根驱动器,是虚拟目录的核心,其他目录都是在这挂载的。
    3. Linux在根驱动器上创建一些特别的目录,就是挂载点。挂载点是虚拟目录下分配额外存储设备的目录。文件和目录存储在挂载点目录上,实际上却存储在另外的驱动器上
    4. 访问一个路径时,会选择一个能最大匹配当前路径前缀的挂载点。比如说,有/var的挂载点,也有/var/run的挂载点的情况下,访问/var/run/test.pid,就会匹配到/var/run挂载点设备下面的/test.pid;
    5. 访问非挂载路径的时候,按照4中所说,其实就是访问最接近的一个挂载点,如果没有其他挂载点就访问根驱动器上的目录或者文件。
    6. 通过挂载点,程序不需要严格区分子目录和独立设备了。这样比如/usr可以是/的子目录,也可以是一个独立的分区,管理起来很灵活。

    所谓挂载,就是可以通过文件系统来访问到你存储设备里面的东西。

    通常系统文件会存储在根驱动器上,而用户文件则存储在另一驱动器中。

    Linux文件结构

    需要和windows的文件系统区分开来

    不是所有逻辑上等的父子关系都必须是同一设备。。。
    决定不同路径对应到不同设备的机制就叫做挂载mount。。
    通过mouth,可以设置当前路径与设备的对应关系。

    你把linux目录结构想象成一棵树,目录就是树枝,分区就是篮子,挂载就是把篮子挂在树枝上,这样你沿着树枝就能进到篮子里获取篮子里的内容。如果篮子没有被挂载到树枝上,你顺着树枝只能拿到一个“空”,也就是null。

    1.3 常见的Linux目录结构

    Linux文件系统是从Unix文件系统结构演进过来的。在Linux文件系统中,通用的目录名用于表示一些常见的功能。

    虚拟目录和文件挂载

    常见的目录名均基于文件系统层级标准(FHS)。很多Linux发行版都遵循了FHS。深入理解linux系统的目录结构(总结的非常详细)

    常见的Linux顶级虚拟目录名及内容:

    目录 用途
    / 虚拟目录的根节点,通常不会存储文件
    /bin 用于存放普通用户可执行的命令
    /boot 用于存放Linux启动必需的文件
    /dev 用于存放系统的设备信息
    /etc 用于存放系统的各种配置
    /home 用于存放系统各个普通用户的主目录
    /lib 用于存放系统和应用程序共享库文件
    /lost+found 文件损坏后找回的文件存放目录
    /media 媒体目录,挂载光盘,U盘等文件系统目录
    /misc 用来挂载NFS共享目录
    /mnt 挂载目录,挂载其他硬盘分区系统的目录
    /opt 可选目录,第三方软件包和数据文件
    /root root用户主目录,普通用户无法访问
    /sbin 存放只有root用户才能运行的系统管理工具
    /tmp 临时目录
    /usr 用来存放供所有用户使用的各种应用程序和数据文件目录,该目录中也有对应的/bin、/lib、/etc等目录
    /var 可变目录,用于存放系统中经常变化的文件

    需要注意的是:我们在一般日常能经常访问的目录:/home/mnt/media/usr

    2. Linux文件系统层次

    Linux文件系统
    • Application Process用户层就是我们日常使用的各种程序,需要的接口主要是文件的创建,删除,打开,关闭,写,读。
    • Virtual File System VFS层 Linux系统分为用户态和内核态,用户态请求硬件需要调用system call通过内核态去实现。用户这些文件操作都有着对应的system call函数接口,接口调用VFS对应的函数。
    • 文件系统层不同的文件系统实现了VFS的这些函数,通过指针注册到VFS里面,所以,用户的操作通过VFS转到各种文件系统。文件系统把文件读写命令转化成对磁盘的LBA(寻址)操作,起到一个翻译和磁盘管理的作用。
    • Page Cache文件系统底下有缓存,Page Cache,加速性能。对磁盘LBA的读写数据缓存到这里。
    • Block Device Driver 块设备区用来访问磁盘LBA的层级,读写命令组合之后插入到命令列,磁盘驱动从队列读命令执行。
    • 磁盘驱动层磁盘的驱动程序把対LBA的读写命令转化为各自的协议,比如ATA命令,SCSI命令,或者是自己硬件可以识别的自定义命令,发送给磁盘控制器。
    • 磁盘物理层读写物理数据到磁盘介质。

    2.1 Virtual File System(虚拟目录系统):

    VFS并不是实际的文件系统。它只存在于内存中,不存在于任何外存空间,VFS在系统启动时创建,在系统关闭时被销毁。

    VFS的作用:就是屏蔽各类文件系统的差异,给用户、应用程序、甚至Linux其他管理模块提供统一的接口集合。

    VFS拥有关于各种特殊文件系统的公共界面,当某个进程发布一个面向文件系统调用时,内核将调用VFS中对应的函数,这个函数处理一些与物理结构无关的操作,并把它重定向为真实文件系统中相应的函数调用。后者处理那些与物理结构相关的操作。

    VFS访问系统

    用户层只能于VFS打交道,而不能直接访问实际文件系统,比如EXT2、EXT3、PROC。

    换句话说,用户层不用也不能区别对待真正的文件系统。

    不过SOCKET虽然也属于VFS的管筹范围,但是有其特殊性,就是不能像打开打开大部分系统的“文件”一样打开socket,它只能被创建,而且在内核中对其特殊性处理。

    2.2 文件系统与工作原理

    在Linux中文件系统的种类很多,主要是VFS做了一个软件抽象层,向上提供文件操作接口,向下提供标准接口供不同文件系统对接。下面以EXT4文件系统为例,讲解下文件系统结构与工作原理。

    存储系统和inode
    数据是保存在磁盘上的,磁盘上最小的存储数据是扇区,每个扇区一般都是可以存放512字节的数据。

    那么如果数据大于521字节的时候,磁盘需要不停地移动磁头来寻找数据,一个文件很容易超过512字节,那么如果将多个扇区合并成一个块,那么磁盘就可以提高效率。磁头一次读取多个扇区就为一个块"block"(Linux上称为块,windows上称为簇)。

    一个块多为4KB,因为块是文件系统上的概念,所以块也可以在格式化时候自行定义。

    文件数据都存储在“块”中我们还必须找到一个地方存储文件的元信息,比如文件的创建者、文件的创建日期、文件的大小等等,这种存储文件元信息的区域就叫做inode(索引节点)。

    每个分区都有自己的文件系统,也有一套属于自己的inode。

    分析EXT4文件系统

    EXT4文件系统
    1. 引导块:磁盘分区的第一个块,记录文件系统分区的一些信息,引导加载当前分区的程序和数据被保存在这个块中,一般占用2KB。
    2. 超级块:超级块用于存储一个已安装的文件系统全局配置参数(例如:块大小,总的块数和inode)和动态信息(例如:当前空闲块数和inode数),其处于文件系统开始位置的1K处,所占大小为1KB,为了系统的健壮性,最初每个块组都有超级块和组描述符表(GDT)一个拷贝,但是当文件很大时,这样浪费很多块(尤其是GDT占用的块多),后来采用了一种稀疏的方式存储这些拷贝,只有快组号是3,5,7的幂的块组才拷贝这个拷贝。通常情况下,只有主拷贝(第0块块组)的超级块信息被文件系统使用,其他拷贝在文件系统被破坏的情况下才使用。
      2.1 块组描述符:GDT用于存储块组描述符,其占用一个或者多个数据块,具体取决于文件系统的大小。它主要包含块位图,inode位图和inode表位置,当前空闲块数,inode数以及使用的目录数。
      2.2 块组:管理系统文件的块、inode分配和管理的状态)每个块组包含一个块位图,一个inode位块图,一个或多个用于描述inode表和用于存储文件数据的数据块。除此之外,还有可能包含超级块和所有块组描述符(取决于块组号和文件系统创建时使用的参数)。
      • 块位图: 用于描述该块组所管理的块的分配状态,如果某个块对应的位未置位,那么代表该块未分配,可以用于存储数据;否则,代表该块已经存储数据或者该块不能够使用。
      • Inode位图:用于描述该块组所管理的inode的分配状态。我们知道inode是用于描述文件的元数据,每个inode对应文件系统中唯一的一个号,如果inode位图中相应位置位,那么代表该inode已经分配出去,否则可以使用,由于其仅占一个块,因此这也限制了一个块组所能够使用的最大inode数量。
      • inode表:用于存储inode信息,占用一个或多个块(为了有效利用空间,多个inode存储在一个块中),其大小取决于文件系统创建时的参数,由于inode位图的限制,决定了其最大所占用的空间。

    以上这几个构成了元素所在磁盘块成为文件系统的元数据块,剩余的部分则用来存储真正的文件内容,称为数据块

    block是实际文件的内容,如果文件大于一个块的时候,将占用多个block,但是一个块只能存放一个文件(因为数据是由inode指向的,如果两个文件数据存放在一个块里,就不能指定)

    2.3 操作系统读取文件

    操作系统读取文件

    大体过程:

    1. 在读取一个文件时,总是从根目录(/)开始读取,每一个目录或者文件,在VFS中,都是一个文件对象,每个文件对象都有唯一的一个inode与之对应。
    2. 读取到第一个inode就是根目录,读取到了该目录后,内核对象就会为该对象建立一个目录项对象(dentry),并将其缓存起来,方便下一次读取时直接从内存中取。
    3. 目录本身也是一个文件,目录文件的内容即是该目录下的文件的名字与inode号,目录文件的内容就像一张表,记录的文件名和其inode之间的映射关系。根据路径即可找到当前需要读取的下一级文件的名字和inode。同时继续为该文件建立dentry。
    4. dentry结构是一种含有指向父节点和子节点指针的双向结构,多个这样双向结构构成了一个内存里面的树状结构,也就是文件系统的目录结构在内存中的缓存。

    一个文件只有一个inode节点存放它的属性信息,那么如果是一个大文件,那么他的block一定是多个,且可能是不连续的,那么inode怎么表示呢?

    大文件的inode

    如果文件内容太大,对应数据库数量过多,inode节点本身提供的存储空间不够,会使用其他间接数据块存储数据块位置信息,最多可以有三级寻址地址。

    1、文件拷贝、剪切的底层过程是怎样的?
    2、软连接和硬连接分别是如何实现的?

    • 复制文件:创建一个新的inode节点,并拷贝数据块的内容
    cp复制
    • 移动文件:同一个分区里面移动文件(mv)inode节点不变,只是更新目录文件对应数据块里面的文件名和inode对应关系跨分区,需要创建新的inode,因为inode节点不同分区是不能共享的。
    A重命名之后inode 同一个分区的inode号不变
    • 软连接:创建软连接会创建一个新的inode节点,其对应的数据块内容存储所链接的文件名信息,这样源文件即便删除了,重新建立一个同名的文件,软连接依然能够生效。
    软连接
    • 硬连接:创建硬连接,并不会新建inode节点,只是links加一,然后在目录文件对应的数据块上增减一条文件名和inode对应的关系记录。只有将硬链接和原文件都删除之后,文件才会真正的删除,即links为0才是真正的删除。

    推荐阅读以及参考:

    理解 Linux 的硬链接与软链接

    linux文件系统详解

    Linux文件系统的目录结构详解

    [文件系统]文件系统学习笔记(三)---目录项缓存dentry

    相关文章

      网友评论

        本文标题:Linux那点事-文件系统

        本文链接:https://www.haomeiwen.com/subject/skjsbqtx.html