Linux文件系统

文件系统的功能规划

内存仅仅是一个缓存数据的地方,进程结束之后,应该存在外部存储中。
在规划文件系统中需要规划以下几点:

  • 文件系统要有严格的组织形式,使得文件能够以块为单位进行存储,这个区域称为存放原始资料的仓库区。
  • 文件系统中也要有索引区,用来方便查找一个文件分成的多个块都存放在了什么位置。
  • 如果文件系统中有的文件是热点文件,近期经常被读取和写入,文件系统应该有缓存层。
  • 文件应该用文件夹的形式组织起来,方便管理和查询。
    在文件系统中,每个文件都有一个名字,这样我们访问一个文件,希望通过它的名字就可以找到。文件名就是一个普通文本。当然文件会进程冲突,不同用户取相同的名字情况还是会经常出现。文件一般都是树形结构,我们将不同的用户放在不同的用户目录下,可以一定程度上避免了命名的冲突问题
    定位文件的时候。
    绝对路径:从根目录开始一直到当前的文件
    相对路径:就是从当前目录开始的文件
  • Linux内核要在自己的内存里面维护一套数据结构,来保存哪些文件被哪些进程打开和使用。

文件系统的相关命令行

  • 格式化
    将一块盘使用命令组织成一定格式的文件系统的过程,windows下,常格式化的格式为NTFS,在Linux下,常用的是ext3或者ext4。
    fdisk -l命令,查看格式化和没有格式化的分区。
    可以通过mkfs.ext3 mkfs.ext4两个命令进行格式化。
    当然,你也可以选择不将整块盘格式化为一个分区,而是格式化为多个分区。下面的这个命令行可以启动一个交互式程序。
    fdisk /dev/vdc
    格式化后的硬盘,需要挂在某个目录下面,才能作为普通的文件系统进行访问。
mount /dev/vdc1 /根目录/用户A目录/目录1

一旦挂在过去,“/根目录/用户A目录/目录1”这个目录下面原来的文件1和文件2就都看不到了,换成vdc1这个硬盘里面的文件系统的根目录。

有挂载就有卸载,卸载使用umount命令

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

linux 里面一切都是文件,ls -l的结果的第一位标识位看出来。

  • - 表示普通文件
  • d表示文件夹
  • c表示字符设备文件
  • b表示块设备文件
  • s表示套接字socket文件
  • l表示符号链接,也即软链接,就是通过名字指向另一个文件,软链接机制后面会讲解

文件系统相关系统调用


#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\n");
    exit(1);
  }


  ret = write(fd, &buffer, sizeof(int));
  if( ret < 0)
  {
    printf("write Error\n");
    exit(1);
  }
  printf("write %d byte(s)\n",ret);


  lseek(fd, 0L, SEEK_SET);
  ret= read(fd, &num, sizeof(int));
  if(ret==-1)
  {
    printf("read Error\n");
    exit(1);
  }
  printf("read %d byte(s),the number is %d\n", ret, num);


  close(fd);


  return 0;
}

当使用系统调用open打开一个文件时,OS会创建一些数据结构来表示这个被打开的文件,为了能够找到这些数据结构,在进程中,我们会为这个打开的文件分配一个文件描述符fd。文件描述符,就是用来区分一个进程打开的文件的。它的作用域就是当前进程,出了当前进程这个文件描述符就没有意义了。open返回的fd必须记录好,我们对这文件的所有操作都要靠fd,包括最后关闭文件。

在Open函数中,有一些参数:

  • O_CREAT 表示当文件不存在,创建一个新的文件
  • O_RDWR 表示以读写方式打开
  • O_TRUNC 表示打开文件后,将文件的长度截短为0

接下来,write要用于写入数据。第一个参数就是fd,第二个参数表示要写入数据存放的位置,第三个参数表示希望写入的字节数,返回值表示成功写入到文件的字节数。

lseek用于重新定位读写的位置,第一个参数就是fd,第二个参数是重新定位的位置,第三个参数是SEEK_SET,表示起始位置为文件头,第二参数和第三个参数合起来表示将读写位置设置为文件头开始0的位置,也就从头开始读写。

read 用于读取数据,第一个参数是fd,第二个参数是读取来的数据存到指向的空间,第三个参数是希望读取的字节数,返回值表示成功读取的字节数。

最终,close将关闭一个文件。

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


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 */
};

函数stat和lstat返回的是通过文件名查到的状态信息。
stat:没有处理符号(软链接)的能力。如果一个文件是符号链接,stat会返回它所指向的文件属性。(穿透)
lstat:返回的就是这个符号链接的内容。(不穿透)
fstat:通过文件描述符获取文件对应的属性。

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


#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\n");
    exit(1);
  }
  while ((direntp = readdir(dirp)) != NULL){
    sprintf(filename, "/root/%s", direntp->d_name);
    if (lstat(filename, &sb) == -1)
    {
      printf("lstat Error%s\n");
      exit(1);
    }


    printf("name : %s, mode : %d, size : %d, user id : %d\n", direntp->d_name, sb.st_mode, sb.st_size, sb.st_uid);


  }
  closedir(dirp);


  return 0
}

opendir函数打开一个目录名所对应的DIR目录流。并返回指向DIR目录流的指针。流定位在DIR目录流的第一条目。

readdir函数从DIR目录流中读取一个项目,返回的是一个指针,指向dirent结构体,且流的自动指向下一个目录条目。如果已经到了流的最后一个条目,怎返回NULL。

close()关闭dir所指的目录流

这样就可以使用系统调用操作文件,也会使用系统调用操作目录了。

总结:

  • 在文件系统上,需要维护文件的严格的格式,要通过 mkfs.ext4 命令来格式化为严格的格式。
  • 每一个硬盘上保存的文件都要有一个索引,来维护这个文件上的数据块都保存在哪里。
  • 文件通过文件夹组织起来,可以方便用户使用。
  • 为了能够更快读取文件,内存里会分配一块空间作为缓存,让一些数据块放在缓存里面。
  • 在内核中,要有一整套的数据结构来表示打开的文件。
  • 在用户态,每个打开的文件都有一个文件描述符,可以通过各种文件相关的系统调用,操作这个文件描述符。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值