文件操作&使用系统调用进行文件操作
硬件级别
- fdisk:将硬盘分区。
- mkfs:格式化磁盘分区。
- fsck:检查维修系统。
操作系统内核中的文件系统函数
类Unix系统中的函数:
kmount(), kumount() (装载/卸载文件系统)
kmkdir(), krmdir() (生成/删除目录)
kchdir(), kgetcwd () (更改目录,获取CWD路径名)
klink(), kunlink() (链接/取消链接文件)
kchmod(), kchown(),kutime() (更改r | w | x权限、使用者、时间)
kcreat(), kopen() (为R、W、RW、APPEND创建/打开文件)
kread(), kwrite() (读写打开的文件)
klseek(), kclose() (lseak/close文件描述符)
ksymlink(), kreadlink() (创建/读取符号链接文件)
kstat(), kfstat(), klstat() (获取文件状态/信息)
kopendir(), kreaddiz() (打开/读取 airectories)
系统调用
用户模式程序使用系统调用来访问内核函数
I/O库函数
C语言提供一系列标准的I/O函数,提高运行效率。详细介绍见:I/O库函数
文件模式I/O: fopen(),fread();fwrite(),fseek(),fclose(),fflush()
字符模式I/O: getc(), getchar(); ugetc(); putc(),putchar()
行模式I/O: gets() , fgets();puts( ) , fputs()
格式化I/O: scanf(),fscanf().sscanf(); printf(),fprintf() , sprintf()
用户命令
每个用户命令实际上是一个可执行程序,通常会调用库I/O函数。
用户命令的处理顺序为:Command => Library I/O function => System call => Kernel Function
sh脚本
详细介绍见:sh脚本
文件I/O操作
-
用户模式下的程序执行操作
FILE *fp = fopen("file", "r");
FILE *fp = fopen("file", "w"); -
fopen()在用户(heap)空间中创建一个FILE结构体,包含一个文件描述符fd、一个fbuf [BLKSIZE]和一些控制变量。
-
fread(ubuf, size, nitem, fp):将nitem个size字节读取到ubuf上。
-
内核中的文件操作:假设非特殊文件的 read(fd, fbuf[ ], BLKSIZE)系统调用。
-
在read()系统调用中,fd是一个打开的文件描述符,它是运行进程的f数组中的一个索引,指向一个表示打开文件的OpenTable。
-
OpenTable包含文件的打开模式、一个指向内存中文件INODE的指针和读/写文件的当前字节偏移量。从 OpenTable的偏移量,计算逻辑块编号1bk。
-
Minode包含文件的内存 INODE。EMODE.i_block[ ]数组包含指向物理磁盘块的指针。文件系统可使用物理块编号从磁盘块直接读取数据或将数据直接写入磁盘块,但将会导致过多的物理磁盘I/O。
-
设备I/O:Io缓冲区上的物理IO最终会仔细检查设备驱动程序,设备驱动程序由上半部分的start_io()和下半部分的磁盘中断处理程序组成。
EXT2文件系统数据结构
- Block#0:引导块 B0是引导块,文件系统不会使用它。它用于容纳从磁盘引导操作系统的引导程序。
- Block#1:超级块(在硬盘分区中字节偏移量为1024) B1是超级块,用于容纳关于整个文件系统的信息。
- Block#2:块组描述块(硬盘上的s_first_data_blocks-1) EXT2将磁盘块分成几个组。每个组有8192个块(硬盘上的大小为32K)。每组用一个块组描述符结构体描述。
- Block#8:块位图是用来表示某种项的位序列,例如:磁盘块或索引节点。
- Block#9:索引节点位图,一个索引节点就是用来代表一个文件的数据结构。
- Block#10:索引(开始)节点块,每个文件都用一个128节点的独特索引节点结构体表示。
- 直接块:指向直接磁盘块;
- 间接块:每个块编号指向一个磁盘块;
- 双重间接块:每个块指向256个磁盘块;
- 三重间接块:对于小型的“EXT2”文件系统,可以忽略这个块。
- 数据块:紧跟在索引节点块后面的是文件存储块。
使用系统调用进行文件操作
系统调用
- 内核 (Kmode)
- 用户 (Umode)
简单的系统调用:
access:检查对某个文件的权限
- chdir:更改目录
- chmod:更改某个文件的权限
- chown:更改文件所有人
- chroot:将(逻辑)根目录更改为路径名
- getcwd:获取CWD的绝对路径名
- mkdir:创建目录
- rmdir:移除目录(必须为空)
- link:将新文件名硬链接到旧文件名
- unlink:减少文件的链接数;如果链接数达到0,则删除文件
- symlink:为文件创建一个符号链接
- rename:更改文件名称
- utime:更改文件的访问和修改时间
以下系统调用需要超级用户权限。
- mount:将文件系统添加到挂载点目录上
- umount:分离挂载的文件系统
- mknod:创建特殊文件
- stat:获取文件状态信息
- open:打开一个文件进行读、写、追加
- close:关闭打开的文件描述符
- read:读取打开的文件描述符
- write:写入打开的文件描述符
- link:将新文件硬链接到旧文件
- unlink:取消某个文件的链接;如果链接文件链接数为0,则删除文件
- readlink:读取符号链接文件的内容;
- symlink:创建一个符号链接
用户模式
(1)用户模式下的程序执行操作
FILE *p = fopen("file", "r"); or FILE *p = fopen( "file", "w");
可以打开一个读/写文件流。
(2) fopen()在用户(heap)空间中创建一个FILE结构体,包含一个文件描述符fd、
一个fbuf[BLKSIZE]和一些控制变量。它会向内核中的kopen()发出一个
fd =open("file",flags=READ or WRITE)系统调用,构建一个OpenTable来表示打开文件示例。OpenTable的mptr指向内存中的文件INODE。
对于非特殊文件,INODE 的i_block数组指向存储设备上的数据块。成功后,fp会指向FILE结构体,其中fd是open()系统调用返回的文件描述符。
(3) fread(ubuf, size,nitem, fp):将nitem个size字节读取到ubuf上,通过:
将数据从FILE结构体的fbuf上复制到ubuf上,若数据足够、则返回。
如果fbuf没有更多数据,则执行(4a)。
(4a)发出read(fd, fbuf, BLKSIZE)系统调用,将文件数据块从内核读取到fbuf上,然后将数据复制到ubuf上,直到数据足够或者文件无更多数据可复制。
(4b)fwrite(ubuf, size, nitem, fp):将数据从ubuf复制到 fbuf。
- 若(fbuf有空间):将数据复制到fbuf上,并返回。
- 若(fbuf已满):发出 write(fd, fbuf, BLKSIZE)系统调用,将数据块写入内核,然后再次写入fbuf。
- 这样,fread()/fwrite()会向内核发出read(/write)系统调用,但仅在必要时发出,而且它们会以块集大小来传输数据,提高效率。同样,其他库I/O函数,如 fgetc /fputc、fgets/fputs、fscanf/fprintf等也可以在用户空间内的FILE结构体中对fbuf进行操作。
内核模式
(5)内核中的文件系统函数:
假设非特殊文件的read(fd, fbuf[], BLKSIZE)系统调用。
(6)在read()系统调用中,fd是一个打开的文件描述符,它是运行进程的fd数组中的一个索引,指向一个表示打开文件的 OpenTable。
(7)OpenTable包含文件的打开模式、一个指向内存中文件 INODE的指针和读/写文件的当前字节偏移量。从OpenTable的偏移量,
计算逻辑块编号lbk。
通过 INODE.i_block[]数组将逻辑块编号转换为物理块编号blk 。
(8)Minode包含文件的内存INODE。EMODE.i_block[]数组包含指向物理磁盘块的指针。文件系统可使用物理块编号从磁盘块直接读取数据或将数据直接写入磁盘块,但将会导致过多的物理磁盘I/O。
(9)为提高磁盘VO效率,操作系统内核通常会使用一组I/O缓冲区作为高速缓存,以减少物理I/O的数量。
(9a)对于read(fd, buf, BLKSIZE)系统调用,要确定所需的(dev, blk)编号,然后查询I/O缓冲区高速缓存,以执行以下操作:
链接文件
- 硬链接文件
ln oldpath newpath
创建从newpath到oldpath的硬链接。
对应系统调用为:
link(char *oldpath, char *newpath)
硬链接文件会共享文件系统中相同的文件表示数据结构(索引节点)。文件链接数会记录链接到同一索引节点的硬链接数量。硬链接仅适用于非目录文件。否则,它可能会在文件系统名称空间中创建循环。
- 符号链接文件(软链接)
ln -s oldpath newpath
创建从newpath到oldpath的软链接或符号链接。
对应的系统调用为:
link(char *oldpath, char *newpath)
newpath是LNK类型的普通文件,包含oldpath字符串。与硬链接不同的是软链接适用于任何文件,包括目录。软链接在以下情况下非常有用。
- 1.通过一个较短的名称来访问一个经常使用的较长路径名称。
- 2.将标准动态库名称链接到实际版本的动态库。