第七、八章学习笔记
作者:互联网
7.1文件操作级别
文件操作分为五个级别:
(1)硬件级别:
- fdisk:将硬件、U盘或SDC盘分区。
- mkfs:格式化磁盘分区,为系统做好准备。
- fsck:检查和维修系统。
- 碎片整理:压缩文件系统中的文件
(2)操作系统中的文件系统函数:每个操作系统内核均可为基本文件操作提供支持。
(3)系统调用:用户模式程序使用系统调用来访问内核函数。
(4)I/O库函数:
(5)用户命令:mkdir、cd、rm、touch、cat等命令,用户使用命令进行文件操作
(6)sh脚本
7.2 文件I/O操作
(1)用户模式下的程序执行操作
FILE *fp = fopen("file","r");
or
FILE *fp = fopen("file","w")
(2) fopen()在用户( heap)空间中创建一个FILE结构体,包含一个文件描述符fd、一个fbuf [BLKSIZE]和一些控制变量。
(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)系统调用,但仅在必要时发出,而且它们会以块集大小来传输数据,提高效率。
(5)内核中的文件操作:假设非特殊文件的 read(fd, fbuf[ ], BLKSIZE)系统调用。
(6)在read()系统调用中,fd是一个打开的文件描述符,它是运行进程的f数组中的一个索引,指向一个表示打开文件的OpenTable。
(7)OpenTable包含文件的打开模式、一个指向内存中文件INODE的指针和读/写文件的当前字节偏移量。从 OpenTable的偏移量,计算逻辑块编号1bk。通过INODE.i_block[ ]数组将逻辑块编号转换为物理块编号blk。
(8) Minode包含文件的内存 INODE。EMODE.i_block[ ]数组包含指向物理磁盘块的指针。文件系统可使用物理块编号从磁盘块直接读取数据或将数据直接写入磁盘块,但将会导致过多的物理磁盘I/O。
(9)为提高磁盘IO效率,操作系统内核通常会使用一组IO缓冲区作为高速缓存,以减少物理I/O的数量。
(9a)对于read(fd, buf, BLKSIZE)系统调用,要确定所需的(dev,blk)编号,然后查询I/O缓冲区高速缓存。
.get a buffer = (dev,blk); .if(buffer's data are invalid){ start_io on buffer; wait for I/O completion; } .copy data from buffer to fbuf"; .release buffer to buffer cache;
(9b)对于write(fd, fbuf, BLKSIZE)系统调用,要确定需要的(dev,blk)编号,然后查询I/O缓冲区高速缓存。
.get a buffer =(dev, b1k) ; write data to the I/O buffer ; . mark buffer as dataValid and DIRTY(for delay-write to disk); . release the buffer to buffer cache;
(10)设备I/O:Io缓冲区上的物理IO最终会仔细检查设备驱动程序,设备驱动程序由上半部分的start_io()和下半部分的磁盘中断处理程序组成。
7.3低级别文件操作
7.3.1分区
一个块存储设备,如硬盘、U盘、SD卡等,可以分为几个逻辑单元,称为分区。各分区均可以格式化为特定的文件系统,也可以安装在不同的操作系统上。大多数引导程序,如GRUB、LILO等,都可以配置为从不同的分区引导不同的操作系统。表有4个条目,每个条目由一个16字节的分区结构体定义,可以分为几个逻辑单元,称为分区。表有4个条目,每个条目由一个16字节的分区结构体定义,即:
struct partition { u8 drive; // 0x80 - active u8 head; // starting head u8 sector; // starting sector u8 cylinder; // starting cylinder u8 sys_type; // partition type u8 end_head; // end head u8 end_sector; // end sector
u8 end_cylinder; // end cylinder u32 start_sector; // starting sector counting from 0 u32 nr_sectors; // number of sectors in partition };
在Linux下进行的创建mydisk的虚拟磁盘映像文件
7.3.2格式化分区
- fdisk只将一个存储设备划分为多个分区。每个分区都有特定的文件系统类型,但是分区还不能使用。为了存储文件,必须先为特定的文件系统准备好分区。该操作习惯上称为格式化磁盘或磁盘分区。在Linux中,它被称为mkfs,表示Make文件系统。Linux支持多种不同类型的文件系统。每个文件系统都期望存储设备上有特定的格式。在Linux中,命令:
mkfs -t TYPE [-b bsize] device nblocks
在一个nblocks设备上创建一个TYPE文件系统,每个块都是bsize字节。如果bsize未指定,则默认块大小为1KB。具体来说,假设是EXT2/3文件系统,它是Linux的默认文件系统。因此,
mkfs -t ext2 vdisk 1440 or mke2fs vdisk 1440
挂载分区:man 8 losetup:显示用于系统管理的losetup 实用工具命令:
(1)用dd命令创建-一个虚拟磁盘映像:
dd if=/dev/zero of=vdisk bs=1024 count=32768 #32K (1KB) blocks
(2)在vdisk. 上运行fdisk来创建一一个分区P1:
fdisk vdisk
输人n(new)命令,使用默认的起始和最后扇区编号来创建一个分区Pl。然后,输人w命令将分区表写人vdisk并退出fdisko vdisk 应包含-个分区P1 [start=2048, end=65535]。该分区的大小是63488个扇区。
(3)使用以下扇区数在vdisk的分区1上创建一个循环设备 :
losetup -o $(expr 2048 * 512) --sizelimit $(expr 65535 * 512) /dev/1oop1vdisk
losetup需要分区的开始字节(start_ sector512) 和结束字节(end_ sector512)。 读者可手动计算这些数值,并在losetup命令中使用它们。可用类似方法设置其他分区的循环设备。循环设备创建完成后,读进程可以使用命令
losetup - a 将所有循环设备显示为/dev/loopN。
(4)格式化/dev/loop1,它是一个EXT2文件系统:
mke2fs -b 4096 /dev/loop1 7936 # mke2fs with 7936 4KB blocks
该分区的大小是63488个扇区。4KB块的扇区大小是63488 /8=7936
(5)挂载循环设备:
mount /dev/ 1oop1 /mnt # mount as loop device
(6)访问作为文件系统一部分的挂载设备:
(cd /mnt; mkdir bin boot dev etc user) # populate with DIRs
(7)设备使用完毕后,将其卸载。
umount /mnt
(8)循环设备使用完毕后,通过以下命令将其断开:
losetup -a /dev/loop1 # detach a loop device.
7.4.2超级快
struct ext2_super_block { u32 s_inodes_count; // Inodes count u32 s_blocks_count; // Blocks count u32 s_r_blocks_count; // Reserved blocks count u32 s_free_blocks_count; // Free blocks count u32 s_free_inodes_count; // Free inodes count u32 s_first_data_block; // First Data Block u32 s_log_block_size; // Block size u32 s_log_cluster_size; // Allocation cluster size u32 s_blocks_per_group; // # Blocks per group u32 s_clusters_per_group; // # Fragments per group u32 s_inodes_per_group; // # Inodes per group u32 s_mtime; // Mount time u32 s_wtime; // Write time u32 s_mnt_count; // Mount count u16 s_max_mnt_count; // Maximal mount count u16 s_magic; // Magic signature // more non-essential fields u16 s_inode_size; // size of inode structure };
第八章 使用系统调用进行文件操作
链接文件分为硬链接文件和软链接文件(符号链接文件)。
硬链接文件:
ln oldpath newpath
创建从newpath到oldpath的硬链接,对应的系统调用为
link(char *oldpath,char *newpath)
软链接文件:
ln -s oldpath newpath #ln command with the -s flag
创建从newpath到oldpath的硬链接,对应的系统调用为
symlink(char *oldpath,char *newpath)
write系统调用
write,就是把缓冲区的数据写入文件中。注意,这里的文件时广泛意义的文件,比如写入磁盘、写入打印机等等。
Linux 中write()的函数原型:
size_t write(int fildes, const void *buf, size_t nbytes);
fildes:文件描述符,标识了要写入的目标文件。例如:fildes的值为1,就像标准输出写数据,也就是在显示屏上显示数据;如果为 2 ,则想标注错误写数据。
*buf:待写入的文件,是一个字符串指针。
nbytes:要写入的字符数。
函数返回值:size_t 返回成功写入文件的字符数。需要指出的是,write可能会报告说他写入的字节比你所要求的少。这并不一定是个错误。在程序中,你需要检查
error已发现错误,然后再次调用write写入剩余的数据。
read系统调用
系统调用read是从文件中读出数据。要读取的文件用文件描述符标识,数据读入一个事先定义好的缓冲区。他返回实际读入的字节数。
Linux中read的函数原型:
size_t read(int fildes, void *buf, size_t nbytes);
fildes:文件描述符,标识要读取的文件。如果为0,则从标准输入读数据。类似于scanf()的功能。
*buf:缓冲区,用来存储读入的数据。
nbytes:要读取的字符数。
返回值:size_t返回成功读取的字符数,它可能会小于请求的字节数。
系统调用open的作用是打开一个文件,并返回这个文件的描述符。
简单地说,open建立了一条到文件或设备的访问路径。如果操作成功,它将返回一个文件描述符,read和write等系统调用使用该文件描述符对文件或
设备进行操作。这个文件描述符是唯一的,他不会和任何其他运行中的进程共享。如果两个程序同时打开一个文件,会得到两个不同的问价描述符。
Linux中open的函数原型有两个:
int open(const char *path, int oflags); int open(const char *path, int oflags, mode_t mode );
path:准备打开的文件或设备名字。
oflags:指出要打开文件的访问模式。
标签:count,文件,八章,第七,分区,fbuf,笔记,u32,size 来源: https://www.cnblogs.com/l993316381-/p/15379940.html