20201317 7.8章学习总结

第7 8章

文件操作

使用系统调用进行文件操作

本章讨论了多种文件系统,解释操作系统中各种操作级别

  1. 文件存储准备存储设备
  2. 内核中的文件系统支持函数
  3. 系统调用
  4. 文件流上的I/O库函数
  5. 用户命令
  6. 各种操作的sh脚本;

系统性概括了各种操作,

  1. 用户空间的文件流读/写到内核空间的系统调用,直到底层的设备I/O驱动程序级别

    描述了低级别的文件操作

描述了低级别的文件操作

介绍了Linux系统的EXT2文件系统

文件操作级别

硬件级别

  1. fdisk 将硬盘、U盘、SDC盘分区
  2. mkfs 格式化磁盘分区,为系统做好准备
  3. fsck 检查和维修系统
  4. 碎片整理: 压缩文件系统的文件

操作系统内核中的文件系统函数

每个操作系统内核均可为基本文件操作提供支持

系统调用

用户使用系统调用访问内核函数

例下列程序可以读取文件的第二个1024字节

I/O库函数

系统调用可以使用户读/写多个数据块,这些数据块只是一系列字节。

他们不知道也不关心数据的意义。用户通常需要读/写单独的字符,行或数据结构记录等。

如果只有系统调用,用户模式程序则必须自己缓冲区执行这些操作。大多数用户会认为非常不方便

C语言库提供了一系列标准的额I/O函数,同时也提高了运行效率。

出了读/写内存位置的sscanf/sprintf函数外,所有其他I/O库函数都建立在系统调用之上,也就是说,他们最终通过系统内核发出实际数据传输的系统调用。

用户命令

实际为可执行程序(cd除外)通常调用库I/O函数,而库I/O函数再发出调用相应的内核函数。

sh脚本

虽然比系统调用更加方便

但是要手动输入命令,如果使用的是GUI ,操作较为繁琐。

文件的I/O操作

文件I/O:由POSIX(可移植操作系统接口)定义的一些函数

无缓冲,每次读写操作都引起系统调用

特点:

核心概念是文件描述符
可访问各种类型文件
标准I/O基于文件I/O实现

文件描述符

每个打开的文件都对应一个文件描述符
文件描述符是一个非负整数。linux为程序中每个打开的文件分配一个文件描述符
文件描述符从0开始分配,依次递增
文件I/O操作通过文件描述符来完成

标准I/O 文件描述符 文件描述符 文件描述字
标准输入流 0 STDIN_FILENO stdin
标准输出流 1 STDOUT_FILENO stdout
标准错误流 2 STDERR_FILENO stderr
文件的打开和关闭

open函数用来创建或打开一个文件

  1. include<fcntl.h>

  2. int open(const char *path,int oflag,…);

    成功时返回文件描述符;出错时返回EOF
    打开文件时使用两个参数
    创建文件时第三个参数指定新文件的权限
    只能打开设备文件,不能通过open()创建

Linux的Ext2文件系统(inode)

磁盘分区后需要进行格式化,操作系统才可以中这个分区,因为每种操作系统设置的文件属性/权限并不相同。

为了存放这些文件所需要的数据,需要将分区进行格式化,成为操作系统能够利用的文件系统格式。

Linux的正规文件系统为Ext2

通常我们可以称呼:一个可被挂载的数据为一个文件系统而不是一个分区

文件系统如何运行

与操作系统的文件数据有关。

较新的操作系统除了文件实际内容外,通常有很多的属性,例如

  • Linux的文件权限(rwx)
  • 文件属性(所有者、群组、时间参数)

文件系统通常将两部分的数据分别存放再不同的块,权限与属性放置在inode中,至于实际数据则放在data block块中,另外还包括一个超级块,会记录到整个文件系统的整体信息包括inode与block总量、使用量、剩余量。

  • super block :记录此文件系统的整体信息,包括inode/block的总量、使用量、剩余量,以及文件系统的格式和相关信息
  • inode:记录文件属性,一个文件占用一个inode,同时记录此文件的数据所在的block号码;
  • block:实际记录文件的内容,当文件太大时,会占用多个block

文件系统的简单操作

磁盘与目录的容量:df,du

df 列出文件系统的整体磁盘使用量

du 评估文件系统的磁盘使用量(常用于评估目录所占容量)

将系统内所有的文件系统列出来

image-20220924145745250

将系统内的所有特殊文件格式及名称都列出来

image-20220924145803310

将目前的各个分区当中可用的inode数量列出

image-20220924145819847

du

  • -a:列出所有文件与目录容量,因为默认仅统计目录下的文件量而已
  • -h:以人们较容易理解的容量格式(G/M)显示
  • -s:列出总量而已,而不列出每个各别的目录占用容量
  • -S:不包括子目录下的总计,与-s有点差别
  • -k:以kb的方式列出容量显示
  • -m:以MB的方式列出容量显示

简单的文件操作

分区

创建mydisk虚拟磁盘映像文件

image-20220924151427398

磁盘映像上,运行disk

image-20220924152342923

格式化分区

fdisk只是将一个存储设备划分为多个分区。每个分区都有特定的文件系统类型,但是分区还不可以使用,为了存储文件,必须先将特定的的文件系统准备好分好区,被称为格式化磁盘或者是磁盘分区

在linux中,被称为是mkfs,也被称为是Make文件系统。

支持不同类型的文件系统。每个文件系统都期待存储设备上有特定的格式。

在一个nblocks设备上创建一个TYPE文件系统,每个块都是bsize字节。

mkfs -t TYPE [-b bsize] device nblocks

以linux的EXT2/3文件系统举例

mkfs -t ext2 vdisk 1440

image-20220924153519563

使用1440(1KB)个块将vdisk格式化为ext2文件系统。

格式化后的磁盘只包括根目录的空文件系统。但是Linux的mkfs始终会在根目录下创建一个默认的lost+found目录

在Linux中,还不能访问新的文件系统。他必须挂载到根文件系统中的现有目录。/mnt目录通常挂载其他文件系统。

由于虚拟文件系统不是真正的设备,他们必须作为循环设备进行挂载。

image-20220924154344355

使用

sudo umount /mnt  #卸载设备,将其与根文件系统分离,设备上保存的文件应留在该设备中。

image-20220924155523625

挂载分区

man 8 losetup:显示用于系统管理的losetup实用工具命令

image-20220924160152457主要实现了

  1. 用dd创建一个虚拟磁盘影响
  2. 在vdisk上创建一个分区p1
  3. 分区大小是63488个扇区

image-20220924161631167

使用扇区数在vdisk的分区15上创建一个循环设备

因为分区1繁忙,所以我们利用sudo losetup -f查找空闲设备

image-20220924161644554

显示所有循环设备

image-20220924161719833

格式化分区15,成为EXT2文件系统

挂载循环设备

访问作为文件系统一部分的挂载设备

image-20220924161733365

设备使用完后,将其卸载

并通过命令断开losetup

使用系统调用进行文件操作

系统调用

在操作系统中,进程以两种不同的模式进行,即内核模式、用户模式,简称Kmode和Umode。

在Umode中进程的权限非常有限,不能执行哪个任何需要的特殊权限操作

特殊权限的操作需要在Kmode中执行。

系统调用(syscall)是一种允许进程进入Kmode以执行Umode不允许操作的机制。复刻子进程、修改执行映像甚至是终止等操作都必须在内核中执行。

系统调用必须由程序发出,他们的用法就像普通函数调用一样,每个系统调用都是一个库函数,它汇集系统调用参数

并最终向操作系统内核发出一个系统调用。

int syscall(int a,int b,int c,int d);
  • access:检査对某个文件的权限
int access(char •pathname, int mode);
  • chdir:更改目录
int chdir(const char *path);
  • chmod:更改某个文件的权限
int chmod(char *path, mode_t mode);
  • chown:更改文件所有人
int chown(char *name, int uid, int gid);
  • chroot:将(逻辑)根目录更改为路径名
int chroot (char *patiiname);
  • getcwd:获取CWD的绝对路径名
char *getcwd(char *buf, int size);
  • mkdir:创建目录
int mkdir(char *pathname, mode_t mode);
  • rmdir:移除目录(必须为空)
int rmdir (char *pathname);
  • link:将新文件名硬链接到旧文件名
int link(char *oldpath, char *newpath);
  • unlink:减少文件的链接数;如果链接数达到0,则删除文件
int uniink(char *pathname);
  • symlink:为文件创建一个符号链接
int symliak(char *oldpath, char *newpath);
  • rename:更改文件名称
int rename(char *oldpath, char *newpath);
  • utime:更改文件的访问和修改时间
int utime(char *pathname, struct utimebuf *time)

以下系统调用需要超级用户权限:

  • mount:将文件系统添加到挂载点目录上
int mount(char *specialfile, char *mountDir);
  • umount:分离挂载的文件系统
int umount(char *dir);
  • mknod:创建特殊文件
int mknod(char *path, int mode, int device);

常见的文件操作的系统调用。

stat:获取文件状态信息

int stat(char *filename, struct stat *buf);
int fstat(int filedes, struct stat *buf);
int lstat(char *filename, struct stat *buf);
  • open:打开一个文件进行读、写、追加
int open(char *file, int flags, int mode);
  • close:关闭打开的文件描述符
int close(int fd);
  • read:读取打开的文件描述符
int read(int fd, char buf[], int count);
  • write:写入打开的文件描述符
int write(int fd, char buf[], int count);
  • lseek:重新定位文件描述符的读/写偏移量
int lseek(int fd, int offset, int whence);
  • dup:将文件描述符复制到可用的最小描述符编号中
int dup(int oldfd);
  • dup2:将oldfd复制到newfd中,如果文件链接数为0,则删除文件
int dup2(int oldfd, int newfd);
  • link:将新文件硬链接到旧文件
int link(char *oldPath, char *newPath);
  • unlink:取消某个文件的链接;如果文件链接数为0,则删除文件
int unlink(char *pathname);
  • symlink:创建一个符号链接
int symlink(char *target, char *newpath);
  • readlink:读取符号链接文件的内容
int readlink(char *path, char *buf, int bufsize);
  • umask:设置文件创建掩码;文件权限为(mask & ~umask)
int umask(int umask);

链接文件

在Unix/Linux系统中,每个文件都有一个路径名,但是Unix/linux系统允许使用不同的路径名来表示同一个文件。

这些文件叫做LINK文件

  • 硬链接
  • 软链接
  • 符号链接

硬链接

ln oldpath newpath

创建从newpath到oldpath的硬链接对应的系统调用是

link(char *oldpath,char *newpath)

硬链接仅用于非目录文件。否则,它可能会在文件系统名称空间中创建循环这是不允许的,相反系统调用:

unlink(char *pathname)

会减少文件的链接数。如果链接被删除为零,文件会被完全删除。这就是rm命令的作用,如果某个文件非常重要,需要创建多个硬链接链接到这个文件中去。

连接文件:ln

在linux,系统上,一般连接文件有两种方式

  1. 一种是类似Windows的快捷功能的文件,可以快速连接到文件中
  2. 通过文件系统的inode连接来产生新文件名,而不是产生新文件 --硬链接

hard link硬链接或者实际链接

每一个文件会占用一个inode,文件内容由inode的记录来指向

想要读取文件,就必须要经过目录文件名来指向到正确的inode号码才能读取

文件名只和目录有关,文件内容则与inode相关。

​ 有没有多个文件名链接到同一个inode号码,就是hard link的由来。

​ 简单来说,hard link只是某个目录下新建一个文件名连接到inode号码中的关联记录

软链接:命令

对应的系统调用是

syslink(char *oldpath,char *newpath)

软链接的一个缺点是目标文件可能不复存在了,这样的话会导致绕行标志会导致司机坠下山崖

在Linux中,会用ls命令以适当的深色RED显示此类危险

遇到的问题

  1. 首先是对于本章内容总体理解出现了问题,对本章的文件操作,具体作用是什么,要干啥?思路不清

答:对于这个问题,我主要参考了《鸟哥的Linux私房菜》,对这个问题有了更加深入的了解。

  1. 其次是在磁盘分区时,出现了问题,显示loop1 busy,无法对loop1进行解决。

答:通过查找网页,翻阅资料,明确了我的问题是在于loop1有问题,处于进程的繁忙中,通过进行命令,

image-20220924161631167

找到了分区中处于空闲状态的loop15,然后可以进行操作了

  1. 挂载分区时出现了问题,找不到disk文件。

答:通过仔细分析代码,和课本中的代码对比,发现了是代码写错了,出现了基础性的问题。

  1. 对于链接文件思路还是不够清晰,从字面意义上讲,不知道这些的作用是什么?

答:主要通过参考了《鸟哥的Linux私房菜》,对这个问题有了更加深入的了解。

反思和总结

​ 本次学习主要涉及了文件操作,对于我的理解来说,非常有困难,底层设计更多地涉及代码、系统调用、系统内核。我认为通过这次学习,我重点在于学会了方法,如何更高效的查找资料,哪一些对我来说是有用的,哪一些我能看懂得,真正学到脑子里的。同时非常高兴的看到了一本书,强推《鸟哥的Linux私房菜》,因为他非常简单明了地把事情讲透了,把知识讲的非常明了,易懂。

​ 下一步,总的来说,还是要多实践、多练习,从实践中发现问题,解决问题。

posted @ 2022-09-25 22:15  B1smarck  阅读(22)  评论(0编辑  收藏  举报