深圳大学操作系统实验四 文件系统

实验目的

 了解Linux 文件命令行操作命令;

了解Linux ext3文件系统上的软硬链接;

实验内容

 可以使用Linux或其它Unix类操作系统;

 学习该操作系统提供的文件系统的命令行接口;

学习文件的软硬链接的使用;

实验环境

 硬件:桌面PC

 软件:Linux 或其他操作系统

实验步骤及说明

学习使用Linux文件系统提供的的ls 、touch、rm、cp、mv、mkdir等命令(希望尽量涵盖各种满足日常编程所需操作),了解EXT2文件系统。

操作部分(参考):

1)   构建以下目录子树:(20%)

2)   创建一个4KB左右的文本文件,其内容为重复出现的“Hello Operating system”。读入该文件的目录项内容,并解读出其对应的inode节点号;然后读出对应的inode内容,找到文件的第一个扇区,读入第一个盘块并查看其内容;(30%)

3)   学习Linux文件系统中关于文件硬链接和软链接的概念和相关操作命令,创建软硬链接各一个,用tree命令、ls -l和ls -i命令查看和对比它们的不同;(10%)

4)   创建一个1GB的大文件,读入全部数据到内存中并记录所花时间,然后进行第二次读入并记录时间。(20%)

要求:用/proc/meminfo查看内存中页缓存使用的变化,并解释两次读入速度差异的原因。

实验报告要求:

1)   按学校统一格式

2)   需要给出具体命令和自行编写的程序的源代码

3)   程序的设计需要给出设计思路或流程框图

4)   实验操作的截图需要有必要的说明文字

选做:

    利用df命令查看并解读文件系统的信息,学习mount/unmount命令如何将光驱或U盘挂载到系统中,并体验windows盘符和linux无盘符概念的差异。

    查看c语言提供的fopen/fclose/fread/fwrite函数和操作系统直接对应的open/close/read/write两套接口的差异,弄清楚字符模式和二进制流模式是哪一层面的概念。

思考文件读写指针(游标概念)属于文件的逻辑抽象管理数据还是属于磁盘文件管理数据?文件指针是否需要保存在磁盘上,如果在磁盘上应该如何存放?如果在内存中又如何存放?

实验结果

1          学习使用Linux文件系统提供的的ls 、touch、rm、cp、mv、mkdir等命令(希望尽量涵盖各种满足日常编程所需操作),了解EXT2文件系统。

1.1          网上查阅资料得知,ls命令是用来显示目标列表的,输出信息可以彩色高亮显示以区分不同类型的文件(图1-1)

图 1‑1 ls指令解释

1.2          Touch命令用于创建新的空文件,并且它还可用于更改现有文件和目录的时间戳(最近访问和修改的日期和时间),其语法是touch [option] file_name(s)(图1-2)。

图 1‑2 touch创建空文件

1.3          Rm命令常用来删除目录里面的一个或多个文件的目录,也用于删除目录下文件与子目录,查阅资料发现其有以下参数(图1-3),图1-4是我们删除的实例。

图 1‑3 rm命令参数

图 1‑4 rm删除实例

1.4          Cp指令用于复制文件或目录,如果指定两个以上的文件或目录,且最后目的地是一个已经存在的目录,他会把前面的所有文件或目录复制到指定目录中,如果目录不存在则报错,且他具有许多参数(图1-5)。

图 1‑5 cp指令参数

1.5          Mv指令是move的缩写,他可以用来移动文件或将文件改名,具体格式是

mv [选项] 源文件或目录 目标文件或目录,具体参数如下(图1-6)。

图 1‑6 mv指令参数

1.6          Mkdir命令常用来创建目录,如果目录名前面没有加任何路径名,则在当前目录下创建由dirname指定的目录,如果给出了一个已经存在的路径,则将会在目录下创建一个指定的目录。命令格式为mkdir [OPTION]... DIRECTORY...,具体参数如下(图1-7)。

图 1‑7 mkdir指令参数

1.7          关于ext4文件系统:目前大部分linux操作系统使用的是ext4文件系统,block是ext4的最小储存单位,使用blkid可以查看文件系统类型,每一个block只能存储一个文件的数据(图1-8)。

图 1‑8 block等基础知识

1.8          EXT3文件系统会把整个分区划分成各个block group,每个块组由superblock,block group,block bitmap,inode bitmap和group descriptor以及inode table、data block组成(图1-9)。

1.8.1     Superblock用于记录文件系统的inode/block总量、使用量、剩余量、大小、以及文件系统的格式和相关信息。

1.8.2     Block bitmap记录所有使用和未使用的block号码,删除文件时,我们需要先从block bitmap中找到对应的block号码,更新标志为未使用,然后释放block。

1.8.3     Inode bitmap,记录使用和未使用的inode号码。

1.8.4     Group descriptor,描述每个区段的开始和结束的block号码,说明每个区段分别介于那些block号码之间。

1.8.5     Inode table,记录该组的所有inode的合集,可以通过inode编号以inode table起始位置做偏移找到inode位置。

图 1‑9 EXT4文件系统分区功能

1.9          我们可以使用dumpe2fs打印ext4分区的详细信息,也可以通过dd了解文件在磁盘中的内容。

2          构建以下目录子树:(20%)

2.1          查阅资料得知,mkdir用于创建目录,默认情况下,ln用于产生硬链接,产生硬链接后目录项中的inode节点相同,即一个inode节点对应两个不通的文件名,两个文件名指向同一个文件;软连接称为符号链接,软连接的两个文件目录项的inode不通,但是他们inode的数据块指向的是目标文件的路径名,删除目标文件会使链接无效,软连接用ln指令的-s参数实现。

2.2          我们根据题意创建目录结构,首先先不考虑e和f文件,因为他们是链接的,不需要创建,所以暂时如下图2-1所示。

图 2‑1 创建没有链接的文件目录结构

2.3          接着我们创建链接(图2-2)。

图 2‑2 创建硬链接和软连接

3          创建一个4KB左右的文本文件,其内容为重复出现的“Hello Operating system”。读入该文件的目录项内容,并解读出其对应的inode节点号;然后读出对应的inode内容,找到文件的第一个扇区,读入第一个盘块并查看其内容;

3.1          根据题目要求,我们首先创建一个helloOS.txt的文件,然后在里面写上重复的Hello Operating system(图3-1)。

图 3‑1 重复hello

3.2          为了解读其节点号,我们查阅资料得知,需要使用df指令,df指令主要来检查文件系统的磁盘空间占用情况,并且-i是来查看inode的节点信息的(图3-2)。

图 3‑2 df参数

3.3          根据当前路径以及所查阅的资料, 我们查询helloOS.txt挂载在哪个文件系统下,我们发现是挂载在sda1文件系统下(图3-3)。

图 3‑3 df -l查看信息

3.4          接着我们根据sda1查看该文件系统的类型,使用df -T的参数(图3-4),发现类型为EXT4。

图 3‑4 查看文件系统类型

3.5          接着我们根据1.9,使用dumpe2fs查看sda1的文件系统的详细信息(图3-5),可以看到如下详细信息:

3.5.1     Inode大小为256字节

3.5.2     每组块存放8192个inode

3.5.3     每个block占用4096字节大小

3.5.4     系统中block总数为20971008个

3.5.5     系统里面inode总数为524880个

3.5.6     每组块里存放了inode的block数目为512块

图 3‑5 dumpe2fs 查看信息

3.6          做个简单的计算,根据上述信息,每个block占用4096个字节,而每个inode占用256字节,4096/256=16,也就是每个块有16个inode,而每组块有512个block有inode,16*512=8192,与上图中inodes per group=8192相吻合。

3.7          根据stat指令简介(图3-6),我们可以使用其查看当前文件inode信息,主要是inode号,可以看到inode号为3804467(图3-7)。

图 3‑6 stat指令

图 3‑7 helloOS的详细信息

3.8          首先计算组号,因为每组有8192个inode,且inode是从1开始计数的,所以(3804467-1)/8192=464(组),根据刚刚dumpe2fs指令的结果,我们可以看到3144271-3415760刚好等于511(图3-8)。

图 3‑8 464组号相关信息

3.9          然后我们根据上述信息计算:

3.9.1     inode表里面的索引值=inode编号%组内inode数目=(3804467-1)%8192=3378。也就是3804467号的inode第464组里面的偏移3378号的inode是目标inode,

3.9.2     因为一个block占4096字节,每个block只能有4096/16=16个inode,所以计算组内盘块号=组内索引/每个盘块有多少个inode=3378/16=211。

3.9.3     该inode在组内291盘块上,对应的偏移也是3378%16=2。

3.9.4     所以最终inode字节位置为(inode表起始盘块+inode组内盘块号)*盘块大小+盘块内偏移*inode大小=(15204384+211)*4096+2*256=62,278,021,632(byte)。

3.10       然后我们通过hexdump工具查看inode的内容(图3-9),结合图3-9我们知道在4字节偏移处为inode大小,查看得知为392,与源文件大小392字节相等,所以证明我们找到了inode(图3-10)。

图 3‑9 ext4的inode结构体

图 3‑10 hexdump查看inode

3.11       查阅资料得知,我们的inode中显示block地址在60字节偏移处(图3-11),此时我们查找60字节偏移处,因为是小端存储,所以块地址为0x00a138ce=10565838(图3-12)。

图 3‑11 inode结构体中block偏移

图 3‑12 查看块地址

3.12       我们尝试使用dd指令读取文件内容块地址为10565838的内容,首先我们先使用debugfs指令检查helloOS.txt文件的所在块号,也是10565838号!说明我们的计算正确,然后使用dd指令输出到out.txt文件中(图3-14),其中if=输入文件;of=输出文件;bs=步长;count=扫描的数目;skip=跳过的块数,并且查看结果(图3-15),发现正是我们文件的内容!

图 3‑13 debugfs检查块号

图 3‑14 dd输出对应快内容

图 3‑15 输出结果

4          学习Linux文件系统中关于文件硬链接和软链接的概念和相关操作命令,创建软硬链接各一个,用tree命令、ls -l和ls -i命令查看和对比它们的不同;

4.1          我们在demo4文件夹中创建soft_and_hard.txt并且对其添加hardlink.txt的硬链接以及softlink.txt的软连接(图4-1),然后通过tree查看链接情况,发现softlink已经软连接到了soft_and_hard上面(图4-2)。

图 4‑1 创建文件以及添加软硬连接

图 4‑2 tree

4.2          然后通过ls -l查看目录下文件信息,发现hard_and_soft的硬链接计数和hardlink计数是相等的,都等于2,根据硬链接的定义,他们都是指向同一个文件的,但是softlink的连接计数为1,也就是被系统当做单独的文件,因为他的inode只记录了原文件的目录,与源文件不同内容的(图4-3),通过ls -i也能验证上述结论,就是hardlink与soft_and_hard有相同的inode号,也就是3804470,而softlink的不同,为3804471(图4-4)。

图 4‑3 ls -l

图 4‑4 ls -i

5          创建一个1GB的大文件,读入全部数据到内存中并记录所花时间,然后进行第二次读入并记录时间。(20%)

要求:用/proc/meminfo查看内存中页缓存使用的变化,并解释两次读入速度差异的原因。

5.1          我们首先使用dd命令创建一个bigFile.txt的大文件,输入为/dev/sda1 输出为该文件,大小为1G(图5-1)。

图 5‑1 dd创建1G大文件

5.2          然后我们编写一个bigfile.c的代码文件,主要思路就是先创建一个1G缓冲区,然后文件流打开并读取,开始计时,读取完毕就结束计时,然后再按照相同操作操作一次(图5-2)。

图 5‑2 bigfile.c

5.3          然后我们打开编译后的bigfile开始测试,首先不读取任何文件(图5-3),然后查看/proc/meminfo信息,可以发现cached有164268KB(图5-4),然后我们继续运行,第一次扫描用时6.53秒,然后查看meminfo发现cached增加到了173372KB(图5-5),然后运行第二次,发现用时比之前快了许多,仅有4.70秒(图5-6)。

图 5‑3 不读取

图 5‑4 meminfo查看cached

图 5‑5 读取一次

图 5‑6 查看meminfo

图 5‑7 读取第二次

5.4          根据上述数据,我们可以得出:由于meminfo的cached页面明显增多,说明第一次读取文件的时候有许多数据进入了cached,然后第二次读取的时候直接读取cached比第一次读取的时候读取磁盘会快很多,虽然不是全部文件都进了cached,但也是优化了1秒多,快了许多。

6          利用df命令查看并解读文件系统的信息,学习mount/unmount命令如何将光驱或U盘挂载到系统中,并体验windows盘符和linux无盘符概念的差异。

6.1          我们在linux系统中直接使用df命令,可以看到第一列为文件系统的名字,第二列指block块的数目总量,第三列是已被使用的block量,第四列是可用块数目,USE%是使用占比,Mounted on是指挂载在哪个目录下,以/dev/sda1为例,他是挂载在”/”目录下的(图6-1)。

图 6‑1 df命令

6.2          根据df参数介绍(图6-2),我们使用df -HT来查看文件系统信息,可以看到相较于df指令,他把size变成了我们常用的KB/MB/GB来划分,并且给出了文件系统的类型和挂载目录(图6-2)。

图 6‑2 df参数介绍

图 6‑3 df -HT

6.3          接着我们关闭虚拟机,在虚拟机中挂载一个iso文件,图中挂载了一个centos的iso文件(图6-4)。

图 6‑4 挂载iso文件

6.4          接着我们开机,可以看到光盘显示在桌面上了(图6-5)。

图 6‑5 iso文件读入

6.5          查看df -h指令,我们可以看到iso文件挂载在了/dev/sr0(图6-6)。

图 6‑6 iso文件挂载目录

6.6          然后由于使用mount指令,我们查阅资料后明白mount的参数使用(图6-7),然后根据这个挂载到/home/liujunnan-2017303010/demo4/cdiso中(图6-8),然后进入cdiso目录查看,发现挂载成功(图6-9)。

图 6‑7 mount参数

图 6‑8 挂载到cdiso目录中

图 6‑9 cdiso目录下文件查看

6.7          我们尝试使用umount命令卸载./cdiso,然后进入iso目录查看(图6-10),发现不挂载进不去(图6-10)。

图 6‑10 卸载后无法进入iso目录

6.8          Linux与windows相比挂载移动存储设备十分不同,windows系统里面对于移动存储设备或者虚拟存储器,系统会自动分配一个盘符作为根目录,我们直接根据盘符访问就可访问文件(图6-11),但是在linux里面需要挂载,因为linux认为阴间设备也是文件,他们有各自文件系统,必须统一文件系统才能访问,这个统一的过程叫做挂载。

图 6‑11 windows挂载

7          查看c语言提供的fopen/fclose/fread/fwrite函数和操作系统直接对应的open/close/read/write两套接口的差异,弄清楚字符模式和二进制流模式是哪一层面的概念。

7.1          查阅资料得知:open/close/read/write是低级IO, 是系统调用函数,而fopen/fclose/fread/fwrite是高级IO,是标准库中的函数,后者是由前者实现的。

7.1.1     open() 打开一个文件并返回它的句柄如果失败,将返回一个小于0的值,原型是int open(const char *path, int access [, unsigned mode]); 参数path是要打开的文件名,access是打开的模式,mode是可选项。表示文件的属性,主要用于UNIX系统中,在DOS/WINDOWS这个参数没有意义。

7.1.2     close() 关闭一个句柄,原型是int close(int handle);如果成功返回0

7.1.3     read() 块读文件,原型是int read(int handle, void *buf, unsigned len);参数buf保存读出的数据,len是读取的字节。函数返回实际读出的字节。

7.1.4     write() 块写文件,原型是int write(int handle, void *buf, unsigned len);参数的含义同read(),返回实际写入的字节。

7.2          1.fopen的原型是:FILE *fopen(const char *filename,const char *mode),fopen实现三个功能

7.2.1     为使用而打开一个流

7.2.2     把一个文件和此流相连接

7.2.3     给此流返回一个FILR指针

7.2.4     参数filename指向要打开的文件名,mode表示打开状态的字符串

7.3          fclose()的功能就是关闭用fopen()打开的文件,其原型是:int fclose(FILE *fp);如果成功,返回0,失败返回EOF。

7.4          fread的功能是从流中读指定个数的字符,原型是size_t fread(void *ptr, size_t size, size_t n, FILE *stream);参数ptr是保存读取的数据,void*的指针可用任何类型的指针来替换,如char*、int *等等来替换;size是每块的字节数;n是读取的块数,如果成功,返回实际读取的块数(不是字节数),本函数一般用于二进制模式打开的文件中。

7.5          fwrite与fread对应,向流中写指定的数据,原型是size_t fwrite(const void *ptr, size_t size, size_t n, FILE *stream);参数ptr是要写入的数据指针,void*的指针可用任何类型的指针来替换,如char*、int *等等来替换;size是每块的字节数;n是要写的块数,如果成功,返回实际写入的块数(不是字节数),本函数一般用于二进制模式打开的文件中。

7.6          对于open与fopen区别:

7.6.1     open是系统调用,返回的是文件句柄,文件的句柄是文件在文件描述副表里的索引,fopen是ANSIC标准中的C语言库函数,返回的是一个指向文件结构的指针)(图7-1)。

7.6.2     fopen用户态下就有了缓存,它使用了FILE这个结构保存缓冲数据。在进行read和write的时候减少了用户态和内核态的切换。而open没有缓存,每次读操作都直接从文件系统中获取数据。在进行read和write的时候每次都需要进行内核态和用户态的切换。

7.6.3     一般用fopen打开普通文件,用open打开设备文件。

图 7‑1 fopen

7.7          我们看看write / read 和 fwrite / fread 的接口(图7-2),read与write作为系统调用,只需要指定读取和写的字节数count即可,但是fwrite与fread需要提供size也就是单个元素的大小,这意味着write/read是二进制流模式,直接读取字节,字符流是fwrite/fread用户层面的,按照对象大小灵活访问数据。

图 7‑2 接口

7.8          一个文件可以以文本模式或二进制模式打开,这两种的区别是:在文本模式中回车被当成一个字符'\n',而二进制模式认为它是两个字符0x0D, 0x0A;如果在文件中读到0x1B,文本模式会认为这是文件结束符,也就是二进制模型不会对文件进行处理,而文本方式会按一定的方式对数据作相应的转换。

7.9          根据上述分析,我们可以推测出,二进制流是系统的层面,不分析单个元素的单位大小,而字符流是用户层面的,用户根据操作系统的二进制数据解析出字符流,解析的时候发生在用户空间。

8          思考文件读写指针(游标概念)属于文件的逻辑抽象管理数据还是属于磁盘文件管理数据?文件指针是否需要保存在磁盘上,如果在磁盘上应该如何存放?如果在内存中又如何存放?

8.1          通过分析fopen我们可以知道,该函数返回一个FILE*类型的指针变量,也就是文件指针。

8.1.1     从概念上来看,文件指针属于逻辑抽象管理数据。

8.1.2     但是从应用上看,linux文件指针存在于PCB中,也就是内存,而不是磁盘中,每次打开新文件都会获得从头开始的文件指针。

8.1.3     如果文件指针保存在磁盘上,则他应该在inode、FAT表或者是block中某个特定的位置,因为文件指针是互斥变量,那么每个block都有指针的话,就不能实现并行。

8.1.4     如果文件指针在内存中,那么必须存放在PCB中,这也意味着多个进程可以以不同进度访问同一个文件,使得系统更加健壮,也让系统支持并行。

四、实验体会:(根据自己情况填写)

通过本次实验,我受益匪浅:

1、   通过对linux文件系统的实验,我明白了ln用于链接文件的作用,并且明白了touch指令用于创建新文件,rm用于删除,cp用于拷贝,mv用于移动重命名,mkdir用于新建目录

2、   明白了EXT2文件系统的基本结构,大部分linux系统都是用的EXT2文件系统,明白了inode的计算方法,明白了使用df查看磁盘空间以及文件系统类型,debugfs查看文件所属盘块,hexdumpfs查看二进制文件内容,dd查看对应盘块内容。

3、   明白了cache对于读写文件的加速效果,以及cache存在的必要性。

4、   明白了可以使用ls -I 和ls -l 查看链接情况,并且每个文件的inode根据软硬连接的不同情况不同。

5、   明白了mount和umount的作用,以及挂载对于linux 的必要性和与windows系统的挂载区别。

6、   明白了linux读写文件的两种不同形式,分别是二进制流形式和字符形式。

  • 22
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值