第7章 文件操作——教材知识点归纳
7.1 文件操作级别
在Linux中,文件操作可以分为五个级别,从最底层到最高层分别如下:
-
硬件级别: 这一级别包括诸如
fdisk
(用于分区)、mkfs
(用于格式化磁盘分区)、fsck
(用于检查系统)以及碎片整理(用于压缩文件系统中的文件)等操作。 -
内核级别的文件系统函数: 这些函数以字母"k"开头,它们提供了从操作系统内核层面支持文件操作的功能。
-
系统调用: 用户模式程序使用系统调用来访问内核函数,常见的系统调用包括
open()
、read()
、lseek()
、close()
等,相关内容将在第8章介绍。 -
I/O库函数: 这些函数使用库函数进行文件操作,详细内容将在第9章介绍。
-
用户命令: 用户可以直接在终端上使用特定的命令进行文件操作。
7.2 文件I/O操作
教材中的图示详细展示了文件操作的原理和执行过程,包括内核层和用户层的操作。
7.3 低级别文件操作
磁盘可以被划分为多个逻辑单元,被称为分区。引导程序可以从不同的分区引导不同的操作系统。其中有一个主引导记录(MBR),它可以将硬盘划分为多个区域,而扩展分区则形成一个链表,对应多个分区。
fdisk
用于对存储设备进行分区。然而,仅使用fdisk
分区后无法直接使用,还需要对分区进行格式化。格式化分区的目的是为特定的文件系统准备分区,以存储文件,这时我们使用mkfs
命令。
7.4~7.5 ext2文件系统
Linux默认使用的文件系统是ext2。ext2文件系统总共包含1440个块,每个块大小为1KB。其中,B0块是引导块,不会被文件系统使用,而是用于容纳引导操作系统时所需的引导程序。
B1块是超级块,用于存储有关整个文件系统的信息。
第8章 使用系统调用进行文件操作——教材知识点归纳
8.1~8.2 系统调用和I/O库函数
操作系统中,进程以两种不同的方式运行:内核模式(Kmode)和用户模式(Umode)。用户模式权限有限,需要在内核模式下执行具有特殊权限的操作。系统调用(System Call)机制允许进程进入内核模式,以执行更高权限的操作。
Linux系统调用手册页存储在/usr/man/
目录中,Ubuntu中存储在/usr/share/man
目录中。
8.3 使用系统调用进行文件操作
系统调用由程序发出,每个系统调用是一个库函数,它们汇集系统调用所需的参数,并最终向内核发出系统调用请求。
系统调用的形式为:int syscall(int a, int b, int c, int d);
其中a为系统调用编号,b、c、d为内核参数。
常用的基础系统调用函数:
int mkdir(char *pathname, int privilege);
用于创建指定名称和权限的目录。如果成功返回1,失败返回-1。int rmdir(char *pathname);
用于删除目录(前提是目录必须为空)。int chdir(char *pathname);
用于更改当前工作路径到指定路径。char *getcwd(char *buf, size_t size);
将当前工作目录的绝对路径复制到指定的内存空间中,参数size表示buf的空间大小。int access(const char *pathname, int mode);
用于判断指定的文件或目录是否存在。int chmod(char *path, mode_t mode);
用于更改文件的权限。int chown(char *name, int uid, int gid);
用于更改文件的所有者。int link(char *oldpath, char *newpath);
用于创建硬链接。int unlink(char *pathname);
用于减少文件链接数,如果链接数为0,则删除文件。int symlink(char *oldpath, char *newpath);
用于创建符号链接。int rename(char *oldpath, char *newpath);
用于重命名文件。int utime(char *pathname, struct utimebuf *time);
用于更改文件的访问时间和修改时间。
8.4 常用的系统调用
常用的文件操作系统调用:
int stat(char *filename, struct stat *buf);
用于获取文件的状态信息。int open(char *file, int flags, int mode);
用于打开文件以进行读取或写入。int close(int fd);
用于关闭已打开的文件描述符。int read(int fd, char buf[], int count);
用于从文件描述符中读取数据。int write(int fd, char buf[], int count);
用于向文件中写入数据。
8.5 链接文件
链接文件的概念是,每个文件都有一个路径名称,但在Linux中,不同的路径可以对应同一个文件。
链接分为两种:硬链接和软链接(符号链接)。
硬链接:
硬链接文件共享相同的文件表示数据结构,适用于非目录
文件。
操作方式:
- 使用命令:
ln oldpath newpath
。 - 使用系统调用:
link(char *oldpath, char *newpath)
。
软链接(符号链接):
软链接是普通文件,其内容是指向链接目标的引用。可以理解为Windows系统下的快捷方式。
操作方式:
- 使用命令:
ln -s oldpath newpath
。 - 使用系统调用:
symlink(char *oldpath, char *newpath)
。
8.6 stat系统调用
stat
函数用于获取文件的状态信息。在使用stat
函数时,首先需要声明一个结构体指针,用于存储返回的文件状态信息。
struct stat {
mode_t st_mode; // 文件的模式(例如文件、目录等)
ino_t st_ino; // inode节点号
dev_t st_dev; // 设备号码
dev_t st_rdev; // 特殊设备号码
nlink_t st_nlink; // 文件的连接数
uid_t st_uid; // 文件所有者的用户ID
gid_t st_gid; // 文件所有者的组ID
off_t st_size; // 普通文件的字节大小
time_t st_atime; // 文件最后被访问的时间
time_t st_mtime; // 文件内容最后被修改的时间
time_t st_ctime; // 文件状态改变的时间
blksize_t st_blksize; // 文件内容的块大小
blkcnt_t st_blocks; // 文件内容的块数量
};
通过使用stat
函数,我们可以获取文件的各种相关信息,这些信息可以通过返回的结构体获取。对于路径,目录也被视为文件,因此也可以获取目录的信息,基于这些信息,我们可以编写自己的简单的ls
程序。
8.7 open-close-lseek系统调用
在C程序中,文件通过描述符来管理。通过文件描述符,可以进行文件的读取和写入操作。
int lseek(int fd, int offset, int whence);
用于重新定位文件描述符的当前偏移量。
8.8~8.10 read()系统调用、write系统调用
read()
函数用于从已打开的文件描述符中读取n个字节到用户控件中的buf[]
中。如果失败,返回-1。write()
函数用于将n个字节从buf
写入已打开的文件描述符,可以是写、读写或追加模式,返回实际写入的字节数,通常等于n。这两个系统调用可以用于实现文件的复制操作。