文件操作

文件操作级别

  1. 硬件级别:
    fdisk将硬盘、U盘或SDC盘分区。
    mkfs:格式化磁盘分区,为系统做好准备。
    fsck:检查和维修系统。
    碎片整理:压缩文件系统中的文件。
  2. 操作系统内核中的文件系统函数
    kmount(),kumount()
    kmkdir(),krmdir()
  3. 系统调用 用户模式使用系统调用来访问内核函数
  4. I/O库函数

除了读/写内存位置的sscanf()/sprintf()函数之外,所有其他I/O库函数都建立在系统调用之上,也就是说,它们最终会通过系统内核发出实际数据传输的系统调用

  1. 用户命令
    用户可以使用Unix/Linux命令来执行文件操作,而不是编写程序。
  2. sh脚本

文件I/O操作(gpt提问)

控制流
(1)用户模式下的程序执行操作
FILE *fp = fopen("file","r");or FILE *fp = fopen("file","w");
(2)fopen在用户(heap)空间中创建一个FILE结构体,向内核中的kopen()发出一个fd = open("file",flags = READ or WRITE)系统调用,构建一个Opentable表示打开文件实例。成功后,fp会指向FILE结构体
(3)fread(ubuf,size,nitem,fp)`:将nitem个size字节读取到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
    (5)内核中的文件系统函数:假设非特殊文件的read(fd,fbuf[],BLKSIZE)系统调用
    (6)read()系统调用中,fd是一个打开的文件描述符,指向一个表示打开文件的OpenTable
    (7)OpenTable包含文件的打开模式、一个指向内存中文件INODE的指针和读/写文件当前字节偏移量
    (8)Minode包含文件的内存INODE
    (9)操作内核通常会使用一组I/O缓冲区作为高速缓存
    (10)设备I/O

低级别文件操作

  1. 分区
    分区表位于第一个扇区的字节446处,该扇区称为设备的主引导记录
    每个扩展分区的第一个扇区是本地MBR.
    Fdisk和分区
    (1)在Linux,创建一个名为mydisk的虚拟磁盘映像文件
    dd if=/dev/zero of = mydisk bs=1024 count=1440
    (2) 在磁盘映像文件上运行fdisk:
    fdisk mydisk

格式化分区

mkfs -t TYPE [-b bsize] device nblocks 创建一个TYPE文件系统
mkfs -t ext2 vdisk1440 或mke2fs vdisk 1440
使用1440(1KB)个块将vdisk格式化为EXT2文件系统

挂载分区

(1)使用dd命令创建一个虚拟磁盘映像:
dd if=/dev/zero of=vdisk bs=1024 count=32768
(2)在vdisk上运行fdisk来创建一个分区P1:
fdisk vdisk

EXT2文件系统简介

EXT2文件系统数据结构

Block#0:引导块

超级块(在硬盘分区中字节偏移量1024)B1是超级块,用于容纳关于整个文件系统的信息

块组描述符 Block#2:块组描述符块。每组用一个块组描述符结构体描述

位图

Block#8:块位图 位图是用来表示某种项的位序列
Block#9:索引节点位图 一个索引节点就是用来代表一个文件的数据结构,

索引节点

Block#10:索引(开始)节点块 每个文件都用一个128字节的独特索引节点结构体表示
直接块
间接块
双重间接块
三重间接块

目录条目

EXT2 目录条目:目录包含dir_entry结构

编程实例

显示超级块
显示位图
显示根索引节点
显示目录条目

使用系统调用进行文件操作

系统调用

是一种允许进程进入Kmode以执行Umode不允许操作的机制

系统调用手册页

Unix、Linux中在线手册页保存在/usr/man/目录中
Ubuntu Linux中,保存/usr/share/man

使用系统调用进行文件操作

由程序发出,每个系统调用都是一个库函数,它汇集系统调用函数,并最终向操作系统内核发出一个系统调用。

简单的系统调用
access:检查对某个文件的权限
int access(char *pathname, int mode);
chdir:更改目录
int chdir(const char *path);
chmod:更改某个文件的权限
int chmod(char path, mode_t mode);
chown:更改文件所有人
int chown(char *name, int uid, int gid)i;
chroot:将(逻辑)根目录更改为路径名
int chroot(char *pathname);
getcwd:获取CWD的绝对路径名
char *getcwd (char *buf, int size);
mkdir:创建目录
int mkdir(char *pathname, mode t mode);
rmdir:移除目录(必须为空)
int rmdir(char *pathname);
link:将新文件名硬链接到旧文件名
int link(char *oldpath, char *newpath);
unlink:减少文件的链接数;如果链接数达到0,则删除文件
int unlink(char *pathname);
symlink:为文件创建一个符号链接
int symlink(char *oldpath, char *newpath);
rename:更改文件名称
int rename(char *oldpath, char *newpath);
utime:更改文件的访问和修改时间
int utime (char *pathname, struct utimebuf *time}

常用的系统调用
open:打开一个文件进行读、写、追加
int open(char *file, int flags, int mode);
close:关闭打开的文件描述符
int close(int fd);
read:读取打开的文件描述符
int read(int fd, char buf[], int count);
write:写入打开的文件描述符
int write(int fd, char buf[], int count);
dup:将文件描述符复制到可用的最小描述符编号中
int dup(int oldfd);
dup2:将oldfd复制到newfd中,如果文件链接数为0,则删除文件
int dup2(int oldfd, int newfd);
link:将新文件硬链接到旧文件
int link(char *oldPath, char *newPath);
unlink:取消某个文件的链接;如果文件链接数为0,则删除文件
int unlink(char *pathname);
symlink:创建一个符号链接
int symlink(char *target, char *newpath);
readlink:读取符号链接文件的内容
int readlink(char *path, char *buf, int bufsize);
umask:设置文件创建掩码;文件权限为(mask & ~umask)
int umask(int umask);
mknod:创建特殊文件
int mknod(char *path,int mode,int device)

链接文件

硬链接文件、软链接
符号链接

硬链接文件 硬链接

符号链接文件 软连接

stat系统调用

stat文件状态
stat、fstat、lstat -fet file status

stat结构体

st_size使用字节表示的文件大小
st_block值是使用512字节表示的文件大小

stat与文件索引节点

每个文件都有一个独有的索引节点数据结构哦,包含文件的所有信息

文件类型和权限

opendir-readdir函数

opendir()返回一个DIR指针dirp。每个readdir(dirp)调用返回一个dirent指针,指向目录中下一个条目的dirent结构体

readlink函数

要想读取符号链接文件的内容,我们必须使用readlink系统调用

ls程序

open-close-lseek系统调用

open:打开一个文件进行读、写、追加
int open(char *file, int flags, int mode);
close:关闭打开的文件描述符
int c1ose(int fd);
read:读取打开的文件描述符
int read( int fd, char buf[], int count);
write:写人打开的文件描述符
int wr⊥te( int fd, char but[], int count)
lseek:将文件描述符的字节偏移量重新定位为偏移量
int lseek(int fd, int offset, int whence);
umask:设置文件创建掩码;
文件权限为(mask&~ umask)
苏格拉底挑战: