一、知识点归纳以及自己最有收获的内容
1、知识点归纳
第7章 文件操作
1、文件操作级别
文件操作分为五个级别,按照从低到高的顺序排列如下
- 硬件级别∶硬件级别的文件操作包括
mkfs∶格式化磁盘分区,为系统做好准备。
fsck∶检查和维修系统。
碎片整理∶压缩文件系统中的文件。
- 操作系统内核中的文件系统函数:每个操作系统内核均可为基本文件操作提供支持。下面列出了类 Unix 系统内核中的一些函数,其中前缀k表示内核函数。
kmkdir(),krmdir()
kchair(),kgetCwd()
klink(),kunlink()
kchmod(),kchown(),kutime()
kcreat(),kopen()
kread(),kwrite()
klseek(),kclose()
keymlink(),kreadlink ()
kstat(),kfstat(),klatat()
kopendir(),kreaddir()
- 系统调用:用户模式程序使用系统调用来访问内核函数。
open()、read()、lseek()和close()函数都是c语言库函数,每个库函数都会发出一个系统调用,使进程进入内核模式来执行相应的内核函数,例如open可以进入kopen(),read可进入kread()函数等。
- I/O库函数:C语言库提供一系列标准的I/O函数,提高运行效率。
I/O库函数包括:
FILE mode I/O:fopen(),fread();fwrite(),fseek(),fclose(),fflush()
char mode I/O:getc(),getchar() ugetc();putc(),putchar()
line mode I/O:gets(),fgets();puts(),fputs()
formatted I/O:scanf(),fscanf(),scanf();printf(),fprintf(),sprintf()
- 用户命令:用户可以使用Unix/Linux命令来执行文件操作。
用户命令的示例如下:
mkdir,rmdir,cd,pwd,ls,link,unlink,rm,cat,cp,mv,chmod,etc.
- sh脚本:用sh语言编写的程序,可通过命令解释程序sh来执行。
2、文件I/O操作
分为内核的以及用户进行的操作
3、低级别文件操作
- 分区
一个块存储设备可以分为几个逻辑单元,称为分区。各分区可以格式化为特定的文件系统,也可以安装在不同的操作系统上。分区表位于第一个扇区的字节便宜446(0x1BE)处,该山区陈伟设备的主引导记录(MBR)。表有四个目录,每个目录由一个16字节的分区结构体定义。 - fdisk将一个存储设备进行分区。而仅仅使用fdisk完成的分区并不能使用,还需要格式化分区。格式化分区的作用是为特定的文件系统准备分区,来存储文件。使用的是mkfs命令。
4、EXT2文件系统
Linux使用的默认文件系统就是ext2。ext2文件系统总共有1440个块,每个块大小1KB。
Block#0:引导块,用于容纳从磁盘引导操作系统的引导程序
Block#1:超级块,用于容纳关于整个文件系统的信息
Block#2:块组描述符块,EXT2将磁盘块分成几个组,每组用一个块组描述符结构体描述
Block#8:块位图,用来表示某种项的位序列
Block#9:索引节点位图,用来代表一个文件的数据结构
Block#10:索引节点块,每个文件都用一个128字节的独特索引节点结构体表示
第8章 使用系统调用进行文件操作
1、系统调用和I/O库函数
操作系统中,进程以两种不同的方式运行:内核模式(Kmode)和用户模式(Umode)。Umode权限有限,特殊权限的操作需要在Kmode下进行。系统调用(System Call)机制允许进程进入Kmode,执行更高权限的操作。
- Linux系统调用手册页保存在/usr/man/目录中,Ubuntu保存在/usr/share/man目录。
2、使用系统调用进行文件操作
系统调用:
int syscall(int a, int b, int c, int d);其中a为系统调用编号,b、c、d都是内核参数。
- 基础系统调用函数:
int mkdir(char *pathname, int privilege);创建以pathname为名的路径,其权限为privilege。返回-1为失败,返回1为成功。
int rmdir(char *pathname);移除目录(此目录必须为空目录)。
int chdir(char *pathname);更改当前路径到pathname。
char *getcwd(char *buf,size_t size);将当前工作目录的绝对路径复制到参数buffer所指的内存空间中,参数size为buf的空间大小。
int access(const char *pathname, int mode);access函数用来判断指定的文件或目录是否存在。
int chmod(char *path, mode_t mode);更改某个文件的权限。
int chown(char *name, int uid, int gid);更改某个文件的所有者。
int link(char *oldpath, char *newpath);链接新文件名到旧文件名(硬链接)
int unlink(char *pathname);减少文件链接数,如果链接数为0,就删除文件
int symlink(char *oldpath, char *newpath);为文件创建一个符号链接
int rename(char *oldpath, char *newpath);重命名文件
int utime(char *pathname, struct utimebuf *time);更改文件访问时间和修改时间。
- 需要超级用户权限:
mount:将文件系统添加到挂载点目录上
umount:分离挂载的文件系统
mknod:创建特殊文件
- 常用系统调用:
int stat(char *filename, struct stat *buf);获取文件状态信息
int open(char *file, int flags,int mode);打开一个文件进行读、写
int close(int fd);关闭打开的文件描述符
int read(int fd, char buf[], int count);读取
int write(int fd, char buf[], int count);写入
3、链接文件
- 链接的含义:每个文件都有一个路径名称,但Linux中允许不同的路径对应同一个文件,这就是链接文件。
链接分为:硬链接、软链接(符号链接) - 硬链接:硬链接文件共享文件系统中相同的文件表示数据结构。硬链接适用于非目录文件。
命令:ln oldpath newpath。
系统调用:link(char *oldpath, char *newpath)
- 软链接(符号链接):newpath是LNK形的普通文件,作为一个绕行标志,使得访问指向链接好的文件。
命令:ln -s oldpath newpath。
系统调用:symlink(char *oldpath, char *newpath)。
4、open-close-lseek系统调用
open:打开一个文件进行读、写、追加
close:关闭打开的文件描述符
read:读取打开的文件描述符
write:写入打开的文件描述符
lseek:将文件描述符的字节偏移量重新定位成偏移量
umask:设置文件创建掩码;文件权限(mask&~umask)
自己最有收获的内容
硬链接与软链接区别和各自特征
- 硬链接特征:
(1)源文件和硬链接文件使用相同的 Inode 和 Block
(2)修改任意一个文件,另一个都改变
(3)删除任意一个文件,另一个都能使用
(4)硬链接标记不清,很难确认硬链接文件位置,不建议使用
(5)硬链接不能链接目录
(6)硬链接不能跨分区 - 软链接特征:
(1)软链接和源文件使用不同的 Inode 和 Block
(2)两个文件修改任意一个,另一个都改变
(3)删除软链接,源文件不受影响;删除源文件,软链接不能使用
(4)软链接没有实际数据,只保存源文件的 Inode,不论源文件多大,软链接大小不变
(5)软链接的权限是最大权限 lrwxrwxrwx.,但是由于没有实际数据,最终访问时需要参考源文件权限
(6)软链接可以链接目录
(7)软链接可以跨分区
(8)软链接特征明显,建议使用软连接
二、问题与解决思路
(1)如果使用库函数有系统调用的开销时,为什么不直接使用系统调用?
解决方法:
这是因为,文件的读写操作通常是大量的数据(大量是底层实现而言),这时,使用库函数可以大大减少系统调用的次数。这一结果源于缓冲区技术,在内核空间和用户空间,对文件操作都使用了缓冲区,例如用fwrite()写文件,都是先将内容写到用户空间缓冲区,当用户空间缓冲去写满或者写操作结束时,才将用户缓冲区的内容写到内核缓冲区,同样的道理,当内核缓冲区写满或者写结束时才将内核缓冲区的内容写到文件对应的硬件媒介上。
(2)实践时出现权限不够的情况
解决方法:
指令前加上sudo后解决问题
三、实践内容与截图
实践1:在Linux下创建一个虚拟磁盘映像文件,并在虚拟磁盘映像文件上运行fdisk
创建名为mydisk的虚拟磁盘映像文件
在磁盘映像文件上运行fdisk
查看帮助文档
写入修改磁盘分区
实践2:mkfs
使用1440(1KB)个块将vdisk格式化为EXT2文件系统
将vdisk挂载到/mnt目录中,随后卸载
实践3:挂载分区
用dd命令创建一个虚拟磁盘映像
创建分区P1
在分区1上创建一个循环设备
格式化/dev/loop9,挂载循环设备,访问挂载设备,然后卸载、断开