Sorry, your browser cannot access this site
This page requires browser support (enable) JavaScript
Learn more >

Gray-Ice

个人博客兼个人网站

本篇博文仅列出本章中提到的标准函数,不会记录RIO包等手写函数。

打开和关闭文件

open()

1
2
#include <fcntl.h>  // 头文件
int open(char *filename, int flags, mode_t mode); // 返回: 若成功则为新文件描述符,若出错为-1。

open函数将filename转换为一个文件描述符,并且返回描述符数字。返回的描述符总是在进程中当前没有打开的最小描述符。flags参数指明了进程打算如何访问这个文件。

  • O_RDONLY: 只读。
  • O_WRONLY: 只写。
  • O_RDWR: 可读可写。

flags参数也可以是一个或者更多位掩码的或,为写提供给一些额外的指示:

  • O_CREAT: 如果文件不存在,就创建它的一个截断的(truncated)(空)文件。
  • O_TRUNC: 如果文件已经存在,就截断它。
  • O_APPEND: 在每次写操作前,设置文件位置到文件的结尾处。
1
2
3
4
5
6
7
8
9
10
11
12
在sys/stat.h中定义的访问权限位
S_IRUSR: 使用者能够读这个文件
S_IWUSR: 使用者能够写这个文件
S_IXUSR: 使用者能够执行这个文件

S_IRGRP: 拥有者所在组的成员能够读这个文件
S_IWGRP: 拥有者所在组的成员能够写这个文件
S_IXGRP: 拥有者所在组的成员能够执行这个文件

S_IROTH: 其他人(任何人)能够读这个文件
S_IWOTH: 其他人(任何人)能够写这个文件
S_IXOTH: 其他人(任何人)能够执行这个文件

close()

1
2
#include <unistd.h>
int close(int fd); // 返回: 若成功则为0,若出错则为-1。

读和写文件(read和write)

1
2
3
#include <unistd.h>
ssize_t read(int fd, void *buf, size_t n); // 返回: 若成功则为读的字节数,若EOF则为0,若出错为-1。
ssize_t write(int fd, const void *buf, size_t n); // 返回: 若成功则为写的字节数,若出错则为-1。

读取文件元数据

应用程序能够通过调用stat和fstat函数,检索到关于文件的信息(有时也称为文件的元数据(metadata))。

1
2
3
4
#include <sys/stat.h>
int stat(const char *filename, struct stat *buf);
int fstat(int fd, struct stat *buf);
// 这两个函数的返回: 若成功则为0,若出错则为-1

stat函数以一个文件名作为输入,并填写一个stat数据结构中的各个成员。fstat是相似的,只不过是以文件描述符而不是文件名作为输入。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/* Metadata returned by the stat and fstat functions */
struct stat {
dev_t st_dev; // Device
ino_t st_ino; // inode
mode_t st_mode; // Protection and file type
nlink_t st_nlink; // Number of hard links
uid_t st_uid; // User ID of owner
gid_t st_gid; // Group ID of owner
dev_t st_rdev; // Device type (if inode device)
off_t st_size; // Total size, in bytes
unsigned long st_blksize; // Block size for filesystem I/O
unsigned long st_blocks; // NUmber of blocks allocated
time_t st_atime; // Time of last access
time_t st_mtime; // Time of last modification
time_t st_ctime; // Time of last change
}

st_size成员包含了文件的字节数大小,st_mode成员则编码了文件访问许可位和文件类型。Linux在sys/stat.h中定义了宏谓词来确定st_mode成员的文件类型:

  • S_ISREG(m)。这是一个普通文件吗?
  • S_ISDIR(m)。这是一个目录文件吗?
  • S_ISSOCK(m)。这是一个网络套接字吗?

读取目录内容

1
2
3
#include <sys/types.h>
#include <dirent.h>
DIR *opendir(const char *name); // 返回: 若成功,则为处理的指针;若出错,则为NULL。

函数opendir以路径名为参数,返回指向*目录流(directory stream)*的指针。流是对条目有序列表的抽象,在这里是指目录项的列表。

1
2
#include <dirent.h>
struct dirent *readdir(DIR *dirp); // 返回: 若成功,则为指向下一个目录项的指针;若没有更多的目录项或出错,则为NULL。如果出错会设置errno。判断readdir究竟是出错还是结束的唯一方法就是判断errno是否改变。

每次对readdir的调用返回的都是指向流dirp中下一个目录项的指针,或者,如果没有更多目录项则返回NULL。每个目录项都是一个结构,其形式如下:

1
2
3
4
struct dirent {
ino_t ino; // inode number
char d_name[256]; // Filename
}

I/O重定向

1
2
#include <unistd.h>
int dup2(int oldfd, int newfd); // 返回: 若成功则为非负的描述符,若出错则为-1。

dup2函数复制描述符表表项oldfd到描述符表表项newfd,覆盖描述符表表项newfd以前的内容。如果newfd已经打开了,dup2会在复制oldfd之前关闭newfd。

共享文件

内核用三个相关的数据结构来表示打开的文件:

  • ***描述符表(descriptor table)。每个进程都有它独立的描述符表,它的表项是由进程打开的文件描述符来索引的。每个打开的描述符表项指向文件表*中的一个表项。
  • ***文件表(file table)**。打开文件的集合是由一张文件表来表示的,所有的进程共享这张表。每个文件表的表项组成(针对我们的目的)包括当前的文件位置,引用计数(reference count)*(即当前指向该表项的描述符表项数),以及一个指向v-node表中对应表项的指针。关闭一个描述符会减少相应的文件表表项中的引用计数。内核不会删除这个文件表表项,直到它的引用计数为零。
  • ***v-node表(v-node table)***。同文件表一样,所有的进程共享这张v-node表,每个表项包含stat结构中的大多数信息,包括st_mode和st_size成员。

本篇完。

评论



愿火焰指引你