第七章、文件操作
一、文件操作级别
文件操作分为五个级别,按照从低到高的顺序排列如下。
(1) 硬件级别:硬件级别的文件操作包括:
·fdisk:将硬盘、U盘或SDC盘分区。
·mkfs:格式化磁盘分区,为系统做好准备。
·fsck:检查和维修系统。
·碎片整理:压缩文件系统中的文件。
其中大多数是针对系统的实用程序。普通用户可能永远都不需要它们,但是它们是创建和维护系统不可缺少的工具。
(2) 操作系统内核中的文件系统函数:每个操作系统内核均可为基本文件操作提供支持。
(3) 系统调用:用户模式程序使用系统调用来访问内核函数。
(4) I/O库函数:系统调用可让用户读、写多个数据块,这些数据块只是一系列字节。
(5) 用户命令:用户可以使用Unix/Linux命令来执行文件操作,而不是编写程序。
(6) sh脚本:虽然比系统调用方便得多,但是必须要手动输入命令,如果使用的是GUI,必须要拖放文件图标和点击指向设备来输入,操作繁琐而且耗时。
二、文件I/O操作
双线上方的上半部分表示内核空间,下半部分表示进程的用户空间。该图显示了进程读/写文件流时的操作序列。控制流用标签(1)到(10)标识,说明如下。
下面的步骤(1)~(46)是用户模式下的操作,步骤(5)~(10)是内核模式下的操作。
(1) 用户模式下的程序执行操作可以打开一个读/写文件流。
(2) fopen()在用户(heap)空间中创建一个FILE结构体,包含一个文件描述符fd、一个fbuf[BLKSIZE]和一些控制变量。
(3) fread(ubuf,size,nitem,fp):将nitem个size字节读取到ubuf上,通过:
·将数据从FILE结构体的fbuf上复制到ubuf上,通过:
·如果fbuf没有更多数据,则执行(4a)。
(4) 文件中的文件系统函数:
假设非特殊文件的read(fd,fbuf[],BLKSIZE)系统调用。
(5) 在read()的系统调用中,fd是一个打开的文件描述符,它是运行进程的fd数组中的一个索引,指向一个表示打开文件的OpenTable.
(6) OpenTable包含文件的打开模式、一个指向内存中文件INODE的指针和读/写文件的当前字节偏移量。从OpenTable的偏移量,
·计算逻辑块编号lbk。
·通过INODE.i_block[]数组将逻辑块编号转换为物理块编号blk。
(7) Minode包含文件的内存INDOE
(8) 为提高磁盘I/O效率,操作系统内核通常会使用一组I/O缓冲区作为高速缓存,以减少物理I/O的数量。磁盘I/O缓冲区管理将在第12章中讨论。
三、低级别文件操作
- 分区
一个块存储设备,如硬盘、U盘、SD卡等,可以分为几个逻辑单元,称为分区。各分区均可以格式化为特定的文件系统,也可以安装在不同的操作系统上。大多数引导程序,如GRUB、LILO等,都可以配置为从不同的分区引导不同的操作系统。分区表位于第一个扇区的字节偏移446(0xlBE)处,该扇区称为设备的主引导记录。
每个拓展分区的第一个扇区是一个本地MBR。每个本地MBR在字节偏移量0X1BE处也有一个分区表,只包含两个条目。第一个条目定义了拓展分区的起始扇区和大小。第二个条目指向下一个本地MBR。所有本地MBR的扇区编号都与P4的起始扇区有关。
- 格式化分区
fdisk只是将一个存储设备划分为多个分区.每个分区都有特定的文件系统类型,但是分区还不能使用。为了存储文件,必须先为特定的文件系统准备好分区。该操作系统习惯上称为格式化磁盘或磁盘分区。
- 挂载分区
Man 8 losetup:显示用于系统管理的losetup实用工具命令:
(1) 用dd命令创建一个虚拟磁盘映像
(2) 在vdisk上运行fdisk来创建一个分区P1
(3) 使用以下扇区数在vdisk的分区1上创建一个循环设备
(4) 格式化/dev/loop1,它是一个EXT2文件系统
(5) 挂载循环设备
(6) 访问作为文件系统一部分的挂载设备
(7) 设备使用完毕后,将其卸载
(8) 循环设备使用完毕后,通过以下命令将其断开
四、EXT2文件系统简介
- EXT2文件系统数据结构
在Linux下,我们可以创建一个包含简单EXT2文件系统的虚拟磁盘,如下文所示。
- 超级快
Block#1:超级块(在硬盘分区中字节偏量为1024)B1是超级块,用于容纳关于整个文件系统的信息。下文说明了超级块结构中的一些重要字段。
- 块组描述符
Block#2:块组描述符块(硬盘上的s_first_data_blocks-1)EXT2将磁盘块分成几个组。每个组有8192个块。每组用一个块组描述符结构体描述。
- 位图
Block#8:块位图
Block#9:索引节点位图
- 索引节点
Block#10:索引(开始)节点块
每个文件都用一个128字节(EXT4中的是256字节)的独特索引节点结构体表示。下面列出了主要索引节点字段。
直接块、间接块、双重间接块、三重间接块
数据块:紧跟在索引节点块后面的是文件存储块。
- 目录条目
EXT2目录条目:目录包括dir_entry结构。
第八章、使用系统调用进行文件操作
一、系统调用
二、系统调用手册页
三、使用系统调用进行文件操作
系统调用必须由程序发出。它们的用法就像普通函数调用一样。每个系统调用都是一个库函数,它汇集系统调用函数,并最终向操作系统内核发出一个系统调用。
四、常用的系统调用
五、链接文件
- 硬链接文件 硬链接:命令 ln oldpath newpath 创建从newpath到oldpath的硬链接。对应的系统调用为:link(char *oldpath, char *newpath) 硬链接文件会共享文件系统中相同的文件表示数据结构(索引节点)。文件链接数会记录链接到同一索引节点的硬链接数量。硬链接仅适用于非目录文件。否则,它可能会在文件系统名称空间中创建循环,这是不允许的。相反,系统调用: unlink(char *pathname)会减少文件的链接数。如果链接数变为0,文件会被完全删除。这就是rm(file)命令的作用。如果某个文件包含非常重要的信息,就最好创建多个链接到文件的硬链接,以防被意外删除。
软链接:命令
ln -s oldpath newpath
创建从newpath到oldpath的软链接或符号链接。对应的系统调用是:
symlink(char *oldpath, char *newpath)
newpath是LNK类型的普通文件,包含oldpath字符串。它可作为一个绕行标志,使访问指向链接好的目标文件。与硬链接不同,软链接适用于任何文件,包括目录。
六、stat系统调用
- stat文件状态
- stat结构体
- stat与文件索引节点 struct ext2_inode{ u16 i_mode; u16 i_uid; u32 i_size; u32 i_atime; u32 i_ctime; u32 i_mtime; u32 i_dtime; u16 i_gid; u16 i_links_count; u32 i_blocks; u32 i_flags; u32 i_reservedl; u32 i_blocks[15]; u32 pad[7]; };//inode=128 bytes in ext2/3 FS; 256 bytes in ext4 每个索引节点在存储设备上都有唯一的索引节点编号(ino)。
- 文件类型和权限
- opendir-readdir函数
- readlink函数 linux的open()系统调用遵循符号链接。因此,无法打开符号链接文件并读取其内容。要想读取符号链接文件的内容,我们必须使用readlink系统调用,即
int readlink(char *pathname,char buf[],int bufsize)
他将符号链接文件的内容复制到bufsize的buf[]中,并将实际复制的字节数返回。 - ls程序
- open-close-lseek系统调用
- 打开文件和文件描述符
- 关闭文件描述符
- lseek文件描述符
- write()系统调用
七、文件操作示例程序
1.显示文件内容
2.复制文件
3.选择性文件复制
八、编程项目:使用系统调用递归复制文件