第10章——系统级IO笔记 下

144 阅读4分钟

@[toc]

读取文件元数据

应用程序能通过调用statfstat函数,检索到关于文件的信息(又称文件的元数据 File Metadata

#include <unistd.h>
#include <sys/stat.h>

int stat(const char* filename, struct stat *buf);
int fstat(int fd, struct stat *buf);

			若成功则返回0,出错则返回-1

其中,struct stat *buf中返回查询到的文件元数据。 对于stat函数,第一个参数是文件名; 对于fstat函数,第一个参数是文件描述符。 在这里插入图片描述

struct stat {
               dev_t     st_dev;       文件的设备编号 
               ino_t     st_ino;       索引结点编号 
               mode_t    st_mode;      文件类型和权限
               nlink_t   st_nlink;     硬链接数 
               uid_t     st_uid;       用户ID
               gid_t     st_gid;       组ID
               dev_t     st_rdev;      设备类型(若此文件为设备文件,则为设备编号
               off_t      st_size;     文件大小
               blksize_t   st_blksize; 文件系统的I/O缓冲区大小
               blkcnt_t   st_blocks;   块数 
               time_t    st_atime;     访问时间 
               time_t    st_mtime;     修改时间 
               time_t    st_ctime;     更改时间 
         }; 

可以根据stat函数来实现一个Linuxstat命令,类似于下图. 在这里插入图片描述 Linux上确实有stat这个命令:

在这里插入图片描述

读取目录内容

应用程序可以用readdir系列函数读取目录内容。如果出错,readdir返回NULL,并设置errno。可惜的是唯一能区分错误和流结束情况的方法是检查自调用readdir以来errno是否被修改过。

#inlcude<sys/types.h>
#include<dirent.h>
 
//以路径名为参数,返回指向目录流的指针,流是针对条目有序列表的抽像。
DIR *opendir(const char *name);
 
//返回的是指向流dirp在下一个目录项的指针,如果没有更多的目录项返回NULL,每个目录项都是一个结构体
struct dirent *readdir(DIR *dirp);
 
//虽然有的linux版本包含了其他数据成员,但这两个对所有系统来说都是标准的。d_name是文件名,
//d_ino是文件位置
struct dirent{
    ino_t d_ino;
    char d_name[256];
}

函数closedir关闭并释放所有资源。
在这里插入图片描述

共享文件

在这里插入图片描述

  • Descriptor table描述符表每个进程都有它独立的描述符表,以文件描述符为索引,每个打开的描述符表项指向打开文件表中的一个表项。

  • Open file table打开文件表:打开文件的集合是由一张文件表来表示的,所偶的进程共享这张表。每个文件表的表项组成包括当前的文件位置、引用计数(reference count)(即档期按指向该表项的描述符表项数),以及一个指向v-node表中对应表项的指针。关闭一个描述符会减少相应的文件表表项中的引用计数。内核不会删除这个文件表表项,直到它的引用计数为零。

  • v-node table:同文件表一样,所有进程共享这张v-node表。每个表项包含stat中的大多数信息,包括st_modest_size

  • 若同一个进程打开2次相同文件,会生成两个不同的打开文件表,与之对应有两个彼此独立的文件描述符,所以可以完全独立地对2个打开文件进行读写。(但是显然一般情况不建议两个同时write,容易把文件变得很乱) 在这里插入图片描述

  • fork会为子进程创建一个与父进程相同的描述符表的副本,并且打开文件表的refcnt会变成2(可见fork函数内部的设计也不是那么简单的完全复制的工作,也有增加refcnt这样的操作),父子进程会共享这同一个打开文件表,因此,文件位置File pos是共享的,这样,当一个进程读入时,另一个进程读时会在新的文件位置去读。(当然父子进程可以自行打开和关闭文件,但这样会变得非常混乱,所以必须要用到引用计数) 在这里插入图片描述 在这里插入图片描述

  • ** 打开文件表的关闭 **:close某一文件描述符,所做的是对该文件描述符对应的那个打开文件表的refcnt进行-1,如果refcnt变成0了,才会删除这个打开文件表。如果fork,所有的进程都需要去close,才能从操作系统的角度真正关闭它。

I/O重定向

include <unistd.h>

int dup2(int oldfd, int newfd);
		若成功则返回非负的描述符,出错返回-1.

dup2函数:复制描述符表表项oldfd到描述符表表项newfd,覆盖描述符表表项new-fd以前的内容。 在这里插入图片描述 在这里插入图片描述 在这里插入图片描述