• 趣谈Linux操作系统学习笔记:第二十七讲


    一、文件系统的功能规划

    1、引子

    咱们花了这么长的时间,规划了会议室管理系统,这样多个项目执行的时候,隔离性可以得到保证。

    但是,会议室里面被回收,会议室里面的资料就丢失了。有一些资料我们希望项目结束也能继续保存,

    这就需要一个和项目运行生命周期无关的地方,可以永久保存,并且空间也要比会议室大的多。

    2、图书馆和文件系统的故事

    3、规划文件系统需要考虑的第一点

    4、规划文件系统需要考虑的第二点

    5、规划文件系统需要考虑的第三点

    6、规划文件系统需要考虑的第四点

    1、如何避免一定程度上的命名冲突问题

    每个文件都有一个名字、这样我们访问一个文件,希望通过它的名字就可以找到

    文件名就是一个普通的文本、当然文件名会经常冲突、不同用户取想用的名字的情况还是会经常出现的

    如图所示,不同的用户的文件放在不同的目录下,虽然很多文件都叫“文件 1”,只要在不同的目录下,就不会有问题

    7、规划文件系统需要考虑的第五点

    二、文件系统的相关命令

    1、首先是格式化

    也即将一块盘使用命令组织成一定格式的文件系统的过程。咱们买个硬盘或者 U盘,经常说要先格式化,才能放文件,说的就是这个。

    2、Linux下查看没有格式化的应硬盘信息

    # fdisk -l
    
    
    Disk /dev/vda: 21.5 GB, 21474836480 bytes, 41943040 sectors
    Units = sectors of 1 * 512 = 512 bytes
    Sector size (logical/physical): 512 bytes / 512 bytes
    I/O size (minimum/optimal): 512 bytes / 512 bytes
    Disk label type: dos
    Disk identifier: 0x000a4c75
    
    
       Device Boot      Start         End      Blocks   Id  System
    /dev/vda1   *        2048    41943006    20970479+  83  Linux
    
    
    Disk /dev/vdc: 107.4 GB, 107374182400 bytes, 209715200 sectors
    Units = sectors of 1 * 512 = 512 bytes
    Sector size (logical/physical): 512 bytes / 512 bytes
    I/O size (minimum/optimal): 512 bytes / 512 bytes

    3、对磁盘进行格式化

    mkfs.ext4 /dev/vdc
    fdisk /dev/vdc

    4、挂在到目录

    mount /dev/vdc1 / 根目录 / 用户 A 目录 / 目录 1

    格式化后的硬盘,需要挂在到某个目录下面,才能作为普通的文件系统进行访问。

    5、卸载挂载

    umount / 根目录 / 用户 A 目录 / 目录 1

    三、文件系统的相关系统调用

    看完了命令行,我们来看一下,如何使用系统调用在操作文件?我们先来看一个完整的例子。

    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <fcntl.h>
    
    
    int main(int argc, char *argv[])
    {
    
    
      int fd = -1;
      int ret = 1;
      int buffer = 1024;
      int num = 0;
    
    
      if((fd=open("./test", O_RDWR|O_CREAT|O_TRUNC))==-1)
      {
        printf("Open Error
    ");
        exit(1);
      }
    
    
      ret = write(fd, &buffer, sizeof(int));
      if( ret < 0)
      {
        printf("write Error
    ");
        exit(1);
      }
      printf("write %d byte(s)
    ",ret);
    
    
      lseek(fd, 0L, SEEK_SET);
      ret= read(fd, &num, sizeof(int));
      if(ret==-1)
      {
        printf("read Error
    ");
        exit(1);
      }
      printf("read %d byte(s),the number is %d
    ", ret, num);
    
    
      close(fd);
    
    
      return 0;
    }

    当使用系统调用open 打开一个文件时,操作系统会创建一些数据结构来表示这个被打开的文件下一节,我们就会看到这些。为了能够找到这些数据结构,在进程中,

    我们会为这个打开的文件分配一个文件描述符 fd(File Descriptor)。文件描述符,就是用来区分一个进程打开的多个文件的,它的作用域就是当前进程,出了当前进程这个文件描述符就没有意义了

    opne返回的fd必须记录好,我们队这个文件的所有操作都要靠这个fd,包括最后关闭文件

    1、open函数

    2、write函数

    3、read函数

    4、lseek函数

    对于命令行来讲,通过 ls 可以得到文件的属性,使用代码怎么办呢?

    我们下面三个函数,可以返回与打开的文件描述符相关的文件状态信息,这个信息将会写到类型为struct stat 的 buf 结构中。

    int stat(const char *pathname, struct stat *statbuf);
    int fstat(int fd, struct stat *statbuf);
    int lstat(const char *pathname, struct stat *statbuf);
    
    
    struct stat {
      dev_t     st_dev;         /* ID of device containing file */
      ino_t     st_ino;         /* Inode number */
      mode_t    st_mode;        /* File type and mode */
      nlink_t   st_nlink;       /* Number of hard links */
      uid_t     st_uid;         /* User ID of owner */
      gid_t     st_gid;         /* Group ID of owner */
      dev_t     st_rdev;        /* Device ID (if special file) */
      off_t     st_size;        /* Total size, in bytes */
      blksize_t st_blksize;     /* Block size for filesystem I/O */
      blkcnt_t  st_blocks;      /* Number of 512B blocks allocated */
      struct timespec st_atim;  /* Time of last access */
      struct timespec st_mtim;  /* Time of last modification */
      struct timespec st_ctim;  /* Time of last status change */
    };
    

     5、stat和lstat的区别

    接下来我们来看,如何使用系统调用列出一个文件夹下面的文件以及文件的属性

    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <fcntl.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <dirent.h>
    
    
    int main(int argc, char *argv[])
    {
      struct stat sb;
      DIR *dirp;
      struct dirent *direntp;
      char filename[128];
      if ((dirp = opendir("/root")) == NULL) {
        printf("Open Directory Error%s
    ");
        exit(1);
      }
      while ((direntp = readdir(dirp)) != NULL){
        sprintf(filename, "/root/%s", direntp->d_name);
        if (lstat(filename, &sb) == -1)
        {
          printf("lstat Error%s
    ");
          exit(1);
        }
    
    
        printf("name : %s, mode : %d, size : %d, user id : %d
    ", direntp->d_name, sb.st_mode, sb.st_size, sb.st_uid);
    
    
      }
      closedir(dirp);
    
    
      return 0
    }
    

    6、opendir函数

    7、readdir函数

    8、closedir函数

    到这里,你应该既会使用系统调用操作文件,也会使用系统调用操作目录了。下一节,我们开始来看内核如何实现的。

     四、总结时刻

    这一节,我们对文件系统的主要功能有了一个总体的印象,我们通过下面这张图梳理一下

    1、在文件系统上,需要维护文件的严格的格式,要通过mkfs.ext4 命令来格式化为严格的格式。

    2、每一个硬盘上保存的文件都要有一个索引,来维护这个文件珊国的数据块都保存在哪里

    3、文件通过文件夹组织起来,可以方便用户使用

    4、为了能够更快读取文件,内存里会分配一块空间最为缓存,让一些数据块放在缓存里面

    5、在内核中,要有一整台的数据结构来表示打开的文件

    6、在用户态,每个打开的文件都是一个文件描述符,可以通过各种文件相关的系统调用,操作这个文件描述符

  • 相关阅读:
    git 配置免密上传,配置ssh key
    spring @value 为什么没有获取到值
    idea 下maven 导入本地jar,以及导入之后 java不能引用问题
    在git远程仓创建项目之后,提交本地项目的使用方法
    mysql 查询数据库参数命令
    spring Existing transaction found for transaction marked with propagation 'never' 解决
    nginx for ubuntu
    spring中for循环中事务
    面向接口编程详解(一)——思想基础
    实战MEF(5):导出元数据
  • 原文地址:https://www.cnblogs.com/luoahong/p/10943864.html
Copyright © 2020-2023  润新知