20201317 7.8章学习总结
第7 8章
文件操作
使用系统调用进行文件操作
本章讨论了多种文件系统,解释操作系统中各种操作级别
- 文件存储准备存储设备
- 内核中的文件系统支持函数
- 系统调用
- 文件流上的I/O库函数
- 用户命令
- 各种操作的sh脚本;
系统性概括了各种操作,
-
用户空间的文件流读/写到内核空间的系统调用,直到底层的设备I/O驱动程序级别
描述了低级别的文件操作
描述了低级别的文件操作
介绍了Linux系统的EXT2文件系统
文件操作级别
硬件级别
- fdisk 将硬盘、U盘、SDC盘分区
- mkfs 格式化磁盘分区,为系统做好准备
- fsck 检查和维修系统
- 碎片整理: 压缩文件系统的文件
操作系统内核中的文件系统函数
每个操作系统内核均可为基本文件操作提供支持
系统调用
用户使用系统调用访问内核函数
例下列程序可以读取文件的第二个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函数用来创建或打开一个文件
-
include<fcntl.h>
-
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 评估文件系统的磁盘使用量(常用于评估目录所占容量)
将系统内所有的文件系统列出来
将系统内的所有特殊文件格式及名称都列出来
将目前的各个分区当中可用的inode数量列出
du
- -a:列出所有文件与目录容量,因为默认仅统计目录下的文件量而已
- -h:以人们较容易理解的容量格式(G/M)显示
- -s:列出总量而已,而不列出每个各别的目录占用容量
- -S:不包括子目录下的总计,与-s有点差别
- -k:以kb的方式列出容量显示
- -m:以MB的方式列出容量显示
简单的文件操作
分区
创建mydisk虚拟磁盘映像文件
磁盘映像上,运行disk
格式化分区
fdisk只是将一个存储设备划分为多个分区。每个分区都有特定的文件系统类型,但是分区还不可以使用,为了存储文件,必须先将特定的的文件系统准备好分好区,被称为格式化磁盘或者是磁盘分区
在linux中,被称为是mkfs,也被称为是Make文件系统。
支持不同类型的文件系统。每个文件系统都期待存储设备上有特定的格式。
在一个nblocks设备上创建一个TYPE文件系统,每个块都是bsize字节。
mkfs -t TYPE [-b bsize] device nblocks
以linux的EXT2/3文件系统举例
mkfs -t ext2 vdisk 1440
使用1440(1KB)个块将vdisk格式化为ext2文件系统。
格式化后的磁盘只包括根目录的空文件系统。但是Linux的mkfs始终会在根目录下创建一个默认的lost+found目录
在Linux中,还不能访问新的文件系统。他必须挂载到根文件系统中的现有目录。/mnt目录通常挂载其他文件系统。
由于虚拟文件系统不是真正的设备,他们必须作为循环设备进行挂载。
使用
sudo umount /mnt #卸载设备,将其与根文件系统分离,设备上保存的文件应留在该设备中。
挂载分区
man 8 losetup:显示用于系统管理的losetup实用工具命令
主要实现了
- 用dd创建一个虚拟磁盘影响
- 在vdisk上创建一个分区p1
- 分区大小是63488个扇区
使用扇区数在vdisk的分区15上创建一个循环设备
因为分区1繁忙,所以我们利用sudo losetup -f查找空闲设备
显示所有循环设备
格式化分区15,成为EXT2文件系统
挂载循环设备
访问作为文件系统一部分的挂载设备
设备使用完后,将其卸载
并通过命令断开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,系统上,一般连接文件有两种方式
- 一种是类似Windows的快捷功能的文件,可以快速连接到文件中
- 通过文件系统的inode连接来产生新文件名,而不是产生新文件 --硬链接
hard link硬链接或者实际链接
每一个文件会占用一个inode,文件内容由inode的记录来指向
想要读取文件,就必须要经过目录文件名来指向到正确的inode号码才能读取
文件名只和目录有关,文件内容则与inode相关。
有没有多个文件名链接到同一个inode号码,就是hard link的由来。
简单来说,hard link只是某个目录下新建一个文件名连接到inode号码中的关联记录
软链接:命令
对应的系统调用是
syslink(char *oldpath,char *newpath)
软链接的一个缺点是目标文件可能不复存在了,这样的话会导致绕行标志会导致司机坠下山崖
在Linux中,会用ls命令以适当的深色RED显示此类危险
遇到的问题
- 首先是对于本章内容总体理解出现了问题,对本章的文件操作,具体作用是什么,要干啥?思路不清
答:对于这个问题,我主要参考了《鸟哥的Linux私房菜》,对这个问题有了更加深入的了解。
- 其次是在磁盘分区时,出现了问题,显示loop1 busy,无法对loop1进行解决。
答:通过查找网页,翻阅资料,明确了我的问题是在于loop1有问题,处于进程的繁忙中,通过进行命令,
找到了分区中处于空闲状态的loop15,然后可以进行操作了
- 挂载分区时出现了问题,找不到disk文件。
答:通过仔细分析代码,和课本中的代码对比,发现了是代码写错了,出现了基础性的问题。
- 对于链接文件思路还是不够清晰,从字面意义上讲,不知道这些的作用是什么?
答:主要通过参考了《鸟哥的Linux私房菜》,对这个问题有了更加深入的了解。
反思和总结
本次学习主要涉及了文件操作,对于我的理解来说,非常有困难,底层设计更多地涉及代码、系统调用、系统内核。我认为通过这次学习,我重点在于学会了方法,如何更高效的查找资料,哪一些对我来说是有用的,哪一些我能看懂得,真正学到脑子里的。同时非常高兴的看到了一本书,强推《鸟哥的Linux私房菜》,因为他非常简单明了地把事情讲透了,把知识讲的非常明了,易懂。
下一步,总的来说,还是要多实践、多练习,从实践中发现问题,解决问题。