文件系统与函数
参考目录:
Linux 内核设计与实现 第13章 虚拟文件系统
Linux 程序设计与实现 第3章 文件操作
内核文件系统主要数据结构:
* 超级块对象 super_block,代表一个具体的已安装文件系统
* 索引结点对象 inode,代表一个具体文件
* 文件对象 file,代表由进程打开的文件
* 目录项对象 dentry, 代表一个目录项,是路径的一个组成部分
* 超级块操作 super_operations,包括内核针对特定文件系统所能调用的方法
* 索引操作 inode_operations, 包括内核针对特定文件所能调用的方法
* 文件操作 file_operations, 包括进程针对已打开文件所能调用的方法
* 目录操作 dentry_operations, 包括内核针对特定目录所能调用的方法
一、文件描述符(file descriptors)
内核通过文件描述符来识别每一个文件。 范围从 0 - OPEN_MAX-1 , 每个进程能够打开的文件数量。
UNIX Shell: <unistd.h>
0 表示输入 STDIN_FILENO
1 表示输出 STDOUT_FILENO
2 表示错误 STDERR_FILENO
二、文件I/O操作
open, create, read, write,ioctl, close
1. 文件打开 open 或创建
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
int open(const char *path, int oflag, ...); int openat(int fd, const char *path, int oflag, ...);
// 当成功时返回file destiptor, -1 失败
参数说明:
* 第一个const char *path 表示是要打开或创建的文件名称
* oflag参数说明此函数多个选择,参数定义在fcntl.h头文件中
O_RDONLY O_WRONLY O_RDWR
2. 创建文件 create
#include <fcntl.h> #include <sys/types.h> #include <sys/stat.h> int create(const char *pathname, mode_t moe);
成功返回文件描述符,失败返回-1
此函数等同于
int open(pathname, O_WRONLY);
3. 关闭文件 close
#include <unistd.h> int close(int fileds);
成功返回0,出错返回-1
4. lseek函数
#include <sys/types.h> #include <unistd.h> off_t lseek(int filedes, off_t offset, int whence);
成功返回新的文件位移,出错为-1
参数解释:
filedes 是文件描述符
如果 whence 是 SEEK_SET, 则将该文件位移量设置为距文件开始处offset个字节
如果 whence 是 SEEK_CUR, 则将该文件的位移量设置为其当前值加offset, offset可为正或负
如果 whence 是 SEEK_END, 则将该文件的位移量设置为文件长度加offset, offset可为正或负
5. read函数
#include <unistd.h>
ssize_t read(int filedes, void buff, size_t nbytes);
// 成功返回读到的字节数,若已到文件尾为0,若出错为-1
6. write 函数
#include <unistd.h> ssize_t write(int filedes, const void *buff, size_t nbytes);
成功为已写的字节数,出错-1
/* 从标准输入中读取,输出到标准输出 */
#include <unistd.h> // read, write 用到的头文件 #include <stdio.h> // printf用到的头文件 #include <stdlib.h> // exit用到头文件 #define BUFFSIZE 4096 int main(void) { int n; char buf[BUFFSIZE]; while ((n = read(STDIN_FILENO, buf, BUFFSIZE)) > 0) if (write(STDOUT_FILENO, buf, n) != n) printf("write error"); if (n < 0) printf("read error"); exit(0); }
7. dup 和 dup2 函数
#include <unistd.h> int dup(int filedes); // 返回新的文件描述,最小值 int dup2(int filedes, int filedes2); // filedes2参数指定新描述符的数值
成功返回新的文件描述符,出错为-1
8. fcntl 函数
#include <sys/types.h> #include <unistd.h> #include <fcntl.h> int fcntl(int fieldes, int cmd, ...);
出错返回-1
fnctl 函数有五种功能:
复制一个现存的描述符(cmd = F_DUPFD)
获得/设置文件描述符标记(cmd = F_GETFD 或 F_SETFD)
获得/设置文件状态标记(cmd = F_GETFL 或 F_SETFL)
获得/设置异步I/O所有权(cmd = F_GETOWN 或 F_SETOWN)
获得/设置记录锁(cmd = F_GETLK, F_SETLK 或 F_SETLKW)
9. ioctl 函数
#include <unistd.h> #include <sys/ioctl.h> int ioctl(int filedes, int request, ...); 出错返回-1,成功则为其他值
三、目录操作<dirent.h>
#include <sys/types.h> #include <sys/stat.h> int stat(const char pathname, struct stat buf); int fstat(int filedes, struct stat *buf); int lstat(const char pathname, struct stat *buf);
成功返回0, 出错为-1
struct stat {
mode_t st_mode; // 文件类型与权限
ino_t st_ino; // i-node 序列号
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; // 最后变更时间
long st_blksize; // 最优IO块大小
long st_blocks; // 512字节分配数
};
#include <sys/types.h> #include <sys/stat.h> #include <stdio.h> #include <stdlib.h> int main(int argc, char *argv[]) { int i; struct stat buf; char *ptr; for (i = 1; i < argc; i++) { printf("%s: ", argv[i]); if (lstat(argv[i], &buf) < 0) { printf("lstat error"); continue; } if (S_ISREG(buf.st_mode)) ptr = "regular"; else if (S_ISDIR(buf.st_mode)) ptr = "directory"; else if (S_ISCHR(buf.st_mode)) ptr = "character special"; else if (S_ISBLK(buf.st_mode)) ptr = "block special"; else if (S_ISFIFO(buf.st_mode)) ptr = "fifo"; else if (S_ISLNK(buf.st_mode)) ptr = "symbolic link"; else if (S_ISSOCK(buf.st_mode)) ptr = "socket"; else ptr = "** unknown mode **"; printf("%s\n", ptr); } exit(0); } /* ➜ filedir ./filetype /etc /dev/tty.Bluetooth-Incoming-Port /dev/sdt /var/spool /bin /dev/profile /etc: symbolic link /dev/tty.Bluetooth-Incoming-Port: character special /dev/sdt: character special /var/spool: directory /bin: directory /dev/profile: character special */
opendir, closedir, readdir, telldir, seekdir
1. opendir 打开目录
/*
* 打开目录并建立目录流
* 成功:返回DIR结构的指针
* 失败:返回NULL
*/
#include <sys/types.h> #include <dirent.h> DIR *opendir(const char *name);
2. readdir 读取类似于链表的目录项
/* * 读取目录 * 成功:返回下一个目录项的指针 * 错误或到达未尾:返回NULL */ #include <sys/types.h> #include <dirent.h> struct dirent * readdir(DIR *dirp);
3. telldir 返回当前位置
/* * 查看当前位置 */ #include <sys/types.h> #include <dirent.h> long int telldir(DIR *dirp);
4. seekdir
5. 关闭目录 closedir
编程练习: 完成扫描目录程序
内核虚拟文件系统(VFS):为用户空间提供了文件和文件系统相关的接口。