虚拟文件系统(VFS)概述:
VFS位于文件系统、和访问文件的系统调用(API)之间,为系统调用访问文件系统提供统一的抽象接口。
不同文件系统连接成一个单一树形结构,分别挂载(自己挂载需要用mount命令)在VFS上,采用POSIX系统调用读写不同的文件系统——使得不同文件系统之间进行数据交换和同时管理非常地方便。文件系统用mount命令挂载举例:
cdrom在Linux中的挂载:mount -t iso9660 /dev/cdrom/mnt/cdrom。nfs的挂载:mount -t nfs 127.0.0.1:/mnt/nfs/mnt/nfs。
文件的访问方式:
- 系统调用(当然不止于访问文件系统)——非缓冲文件操作。
- ANSI C库函数——缓冲文件操作(就是输入输出操作等)。
文件流:三个标准流stdin、stdout、stderr,对应的文件描述符0、1、2,其作用是:
- 实现了不同输入输出的格式转换。
- 缓冲功能,使得数据可以集中读写处理,减少系统调用次数。
缓冲有三种:
- 全缓冲:在缓冲区满或者调用刷新函数后,才会进行I/O系统调用(即输入输出)。
- 行缓冲:缓冲区满或者遇到换行符,才I/O系统调用。
- 无缓冲(不输出):如标准出错流。
#include <stdio.h>一些常用的库函数:
打开文件:FILE *fopen(文件名,打开模式mode),成功打开则返回文件流指针,否则返回NULL。所谓打开文件,就是为文件申请一个文件缓冲区和一个FILE结构体,可以通过FILE流指针操纵。具体的打开模式如下:
- "r"或者"rb"(只读):打开一个二进制/文本文件,读取数据。只能打开已存在文件。
- "w"或者"wb"(只写):打开或建立一个二进制/文本文件,写入数据。若文件存在,则将文件中数据清空,再写入;若不存在,则新建一个文件,写入。
- "a"或者"ab"(追加):打开或新建一个二进制/文本文件,追加数据。就是说,只写嘛。
- "r+"或者"rb+"(可读可写):打开一个二进制/文本文件,读写数据。只能打开已存在文件。
- "w+"或者"wb+"(可读可写):新建一个二进制/文本文件,读写数据。
- "a+"或者"ab+"(可读可写):打开或新建一个二进制/文本文件,追加数据。
向文件写入n段数据:int fwrite(字符串,字符串长度size,n,文件流指针),写入n段数据,每段长度为size(一般就一段)。写入成功则返回实际写入段数,否则返回0。
从文件中读取n段数据:int fread(char buf[],unsigned size,unsigned n,FILE *fp),其实fread和fwrite的参数一样,读取的数据根据段数,一次保存在buf中。读取成功则返回实际读取段数,否则返回0。
移动文件读写指针:int fseek(文件流指针,偏移量,参照位置),和系统调用lseek不同(注意参照位置和偏移量,两个函数相反)。返回值也不一样,移动成功则返回0,否则返回非0。
文件描述符和文件流的相互转换:
- 文件流—>文件描述符:int fileno(FILE*stream),成功则返回文件描述符,否则返-1。
- 文件描述符—>文件流:FILE *fdopen(int fileD,模式),成功则返回新的文件流,否则返回NULL。
字符串格式化:int sprintf(目的字符串,格式,源字符串1,...),返回格式化后,目的字符串的长度,例如:
char source[] = "yangwen";
char dest[] = "";
sprintf(dest, "This is %s\n", source); //然后source保持不变,dest变成格式+source
系统调用:
文件操作:
打开文件:int open(文件名,文件操作类型flag),返回文件描述符,否则返回-1。int open(文件名,文件操作类型flag,打开权限mode)。flag一般为O_WRRD就行了,而mode有所有者、用户组、其他用户权限,第三个参数一般在打开文件不存在,flag为O_CREAT时,才会用到,可以使用八进制的方式,如0777,也可以用宏,如S_IRWXU——文件所有者具有可读可写可执行权限。
关闭文件:int close(文件描述符),关闭用open打开的文件,所以参数,文件描述符为open返回过的。
管理文件:int fcntl(文件描述符,操作cmd,...),常用操作有:F_DUPFD:复制文件描述符,F_GETFD、F_SETFD:获取或者设置文件描述符的close_on_exec标志?(什么东西),F_GETFL、F_SETFL:获取文件描述符的操作类型flag。
将size个字节的字符串写入文件:size_t write(文件描述符,字符串,字符串大小size),成功则返回实际写入的字符串大小(在0-size之间),否则返回-1。
读取文件中前size个字节的内容,并保存到字符串中:read(文件描述符,字符串,字符串大小size),而且只要open不更改打开模式,默认情况会在文件内容为空时,阻塞进程;成功则返回实际读到的字符串大小(当然,肯定在0-'字符串大小'之间),否则返回-1。
设置正在读写的文件的,指针指向的位置:off_t lseek(文件描述符,设置的参照位置,偏移量),其中参照位置并非指针最终位置,最终位置=参照位置+偏移量(相对于参照位置),具体的参照位置不能随便给,有三个选项:SEEK_SET文件开头位置0、SEEK_CUR当前位置1、SEEK_END文件末尾位置2。设置成功则返回文件头到设置的位置的偏移差(以字节为单位),否则返回-1。
目录操作:
打开目录:DIR *opendir(目录名)。成功则返回目录流指针,否则返回NULL。
每调用一次,就返回目录流下一个数据项(文件)的数据结构指针:struct dirent *readdir(目录流)。当读取错误或者已到目录尾时,返回NULL。获得目录流中,指向的文件的名称:dirent->d_name(为一个字符串)。
获得目录流中数据项指针的当前指向位置(就是目录下的哪个文件):long int telldir(目录流指针)。设置位置:void seekdir(目录流指针,位置long int loc)。
创建目录:int mkdir(目录名,打开模式mode),mode相当于<打开文件open函数的mode>设置为O_CREAT。成功则返回0,否则返回-1。删除目录:int rmdir(目录名),要求目录为空(即目录下没有文件)。成功则返回0,否则返回-1。
将当前目录名称保存到指定变量buf中:char *getcwd(char *buf,buf数组的大小size),因为要将目录名(绝对路径)保存到buf数组中,所以buf数组的大小必须比目录名大1。所以成功获取则返回buf数组(或者说这个指针),否则就返回NULL(size部队)。
更改目录:int chdir(新目录名)。成功则返回0,否则返回-1。
文件属性管理:
获取文件的状态信息:
int fstat(文件描述符,struct stat *buf),将文件信息保存在指向的stat结构体中。
int stat(文件名,struct stat *buf)、int lstat(文件名,struct stat *buf)。对于普通文件,此二者无差;而对于软链接,stat直接返回链接文件的文件信息,而lstat返回指向文件的信息。
stat结构体的主要内容:
- st_mode:文件权限和文件类型
- st_ino:与文件关联的inode值
- st_dev:文件设备号,代表文件保存在哪个设备上
- st_uid:文件属主的用户ID号
- st_gid:文件属主的组ID号
- st_atime:文件上次被访问时间
- st_ctime:文件属性上次被修改时间(就是文件stat属性被更改)
- st_mtime:文件内容上次被修改时间
- st_nlink:文件硬链接个数
UID、GID向文件拥有者、拥有者组名转换:
由于文件的属性stat中只有两个ID,而没有对应的用户名和组名,所以需要使用另外两个结构体passwd、group,通过它们来获得对应的名称。
UID——>用户名:struct passwd *getpwnam(文件名);struct passwd *getpwuid(uid_t uid)。例如,现在获得了一个struct passwd *ptr,那么获得用户名ptr->pw_name、密码ptr->pw_passwd、目录名(绝对路径名)ptr->pw_dir。
GID——>组名:struct group *getgrnam(文件名);struct group *getgruid(gid_t gid)。获得组名ptr->gr_name、密码ptr->gr_passwd。
获取软链接指向的文件名称:int readlink(软链接名称,字符串buf,大小size),将链接文件的指向文件的绝对路径保存到字符串buf中。成功则返回绝对路径的长度。如果路径长度超过字符串大小size,超过的内容将会被截断。
判断文件是否具有某种操作属性(读写):int access(文件名,执行权限mode),执行权限mode有:R_OK可读、W_OK可写、X_OK可执行、F_OK文件存在。如果符合判断,则返回0,如果有一个条件不满足,则返回-1。
测试文件类型:int isfdtype(文件描述符,文件类型)。如果是,则返回1,否则返回0,出错则返回-1。第二个参数——文件类型如下:
这些参数和一系列测试宏对应(不是真的对应,只是为了方便记忆:是这样的,这些参数的形状是S_IFXXX,而测试宏是S_ISXXX),如S_ISDIR(stat.st_mode),通过获得的文件属性stat的st_mode成员来测试这个文件是否为目录,如果是则返回1,否则返回0。