阅读分享 -- 《Linux 系统编程 第二版》III
书接上回II 阅读分享 -- 《Linux 系统编程 第二版》II|ZklMao-Space (zklkk.online) 这部分主要分享的是文件属性和目录,也就是书的第八章部分。
概述
这章内容不多,主要用得比较多就stat(...) 函数族,inotify_ ...() 文件监视函数族,含有软硬连接link(...) unlink(...) symlink(...) 其他文件操作函数在下面简单罗列...
stat(...)结构体
<sys/stat.h>
struct stat {
dev_t st_dev; /* ID of device containing file */
ino_t st_ino; /* inode number */
mode_t st_mode; /* permissions */
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 ID (if special file) */
off_t st_size; /* total size in bytes */
blksize_t st_blksize; /* block size for filesystem I/O */
blkcnt_t st_blocks; /* number of blocks allocated */
time_t st_atime; /* last access time */
time_t st_mtime; /* last modification time */
time_t st_ctime; /* last status change time */
};
结构体成员说明
- 文件设备信息
st_dev
:表示文件所在的设备编号。st_rdev
:如果文件是特殊设备文件,则表示设备编号。
- 索引节点信息
st_ino
:文件的索引节点编号,用于唯一标识文件。
- 文件权限和属性
st_mode
:文件的权限模式,包括文件类型、读写执行权限等。st_nlink
:文件的硬链接数量。st_uid
和st_gid
:分别表示文件所有者的用户 ID 和所属组的组 ID。
- 文件大小和块信息
st_size
:文件的大小,以字节为单位。st_blksize
:文件系统进行 I/O 操作的首选块大小。st_blocks
:分配给文件的块数量。
- 文件时间信息
st_atime
:文件的最后访问时间。st_mtime
:文件的最后修改时间。st_ctime
:文件的最后状态改变时间,通常是指文件的权限、所有者等属性发生改变的时间。
stat(...) 函数族
这张就这几个函数:
#include <sys/stat.h>
// 获取指定路径的文件信息,包括文件类型、权限、所有者、组、大小、修改时间等,并将信息存储在 `stat`结构体中
int stat(const char *restrict pathname,
struct stat *restrict statbuf);
// 通过文件描述符获取文件的相关信息,其功能与 `stat`函数类似,但参数是文件描述符而不是文件路径。
int fstat(int fd, struct stat *statbuf);
// 与 `stat`函数类似,但对于符号链接,`lstat`函数返回的是符号链接本身的信息,而不是链接所指向的文件的信息。
int lstat(const char *restrict pathname,
struct stat *restrict statbuf);
#include <fcntl.h> /* Definition of AT_* constants */
#include <sys/stat.h>
// 该函数用于获取指定路径的文件状态信息,并将这些信息存储在 statbuf 所指向的 stat 结构体中
int fstatat(int dirfd, const char *restrict pathname,
struct stat *restrict statbuf, int flags);
其他文件操作函数
文件权限管理
int chmod(const char *path, mode_t mode)
int fchmod(int fd, mode_t mode)
int chown(const char *path, uid_t owner, gid_t group)
int lchown(const char *path, uid_t owner, gid_t group)
int fchown(int fd, uid_t owner, gid_t group)
int rename(const char *oldpath, const char *newpath)
....
目录相关函数
char* getcwd(char *buf, size_t size) :获取当前工作目录的绝对路径,并将其存储在buf所指向的缓冲区中。
char* get_current_dir_name(void):获取当前工作目录的路径名。与 `getcwd`函数类似,但在某些情况下使用更方便,例如不需要指定缓冲区大小。
int chdir(const char *path) 功能描述:将当前工作目录更改为path指定的目录。
int fchdir(int fd) :通过文件描述符fd来更改当前工作目录。fd必须是一个打开的目录文件描述符。
int mkdir(const char* path, mode_t mode)* :创建一个新的目录,目录路径由path指定,mode参数指定了新目录的权限。
int rmdir(const char* path) :*删除指定的空目录,path为要删除的目录路径。
DIR* opendir(const char *name) :打开指定名称的目录,并返回一个指向DIR结构体的指针,该结构体用于后续读取目录内容。
struct dirent* readdir(DIR *dir) :从由dir指向的目录流中读取下一个目录项,并将其信息存储在dirent结构体中。返回值为指向dirent结构体的指针,当读取完所有目录项时返回NULL。
int closedir(DIR *dir) :关闭由opendir函数打开的目录流
文件监视事件
struct inotify_event
结构体
struct inotify_event{
int wd; // Watch descriptor on which event occured
uint32_t mask; // Bits describing event that occured #发生发事件掩码 - 具体见下mask 表
uint32_t cookie; // Cookie for related events (for rename())
uint32_t len; // Size of 'name' field # 下面name[]数组 长度
char name[]; // Optional null-terminated filename # 变更的文件名
};
int inotify_init1(...)
int inotify_init1(int flags) : 初始化一个 inotify 实例,并返回一个文件描述符,该文件描述符将用于后续的 inotify 操作.
flags
:可选的标志参数(可不填),目前支持的标志包括IN_CLOEXEC
和IN_NONBLOCK
。IN_CLOEXEC
表示在执行新的程序时关闭该文件描述符;IN_NONBLOCK
表示将文件描述符设置为非阻塞模式。
int inotify_add_watch(...)
- int inotify_add_watch(int fd, const char *path, uint32_t mask) :在指定的 inotify 文件描述符
fd
上,为指定的文件或目录path
添加一个监视,并指定要监视的事件掩码mask
. fd
:之前通过inotify_init1
函数获取的 inotify 文件描述符.path
:要监视的文件或目录的路径名.mask
:事件掩码,用于指定要监视的事件类型,是一个由多个事件标志组成的位掩码。可选参数见下:
mask |
---|
IN_ACCESS 文件被访问 |
IN_ATTRIB 文件元数据改变 |
IN_CLOSE_WRITE 关闭为了写入而打开的文件 |
IN_CLOSE_NOWRITE 关闭只读方式打开的文件 |
IN_CREATE 在监听目录内创建了文件/目录 |
IN_DELETE 在监听目录内删除文件/目录 |
IN_DELETE_SELF 监听目录/文件本身被删除。 |
IN_MODIFY 文件被修改 |
IN_MOVE_SELF 受监控目录/文件本身被移动 |
IN_MOVED 文件被移 |
IN_OPEN 文件被打开 |
IN_ALL_EVENTS 以上所有输出事件的统称 |
int inotify_rm_watch(...)
- int inotify_rm_watch(int fd, uint32_t wd) :从指定的 inotify 文件描述符
fd
中删除指定的监视描述符wd
。
- 参数
fd
:之前通过inotify_init1
函数获取的 inotify 文件描述符。wd
:要删除的监视描述符,是通过inotify_add_watch
函数返回的唯一标识符
read(...)
int read(int fd, void* event, size_t len);
# 若不在notify_init1() 指定参`IN_NONBLOCK`则默认初始换创建的监听描述符默认为阻塞模式。数读取内核返回的变化事件的字节数据。一般传入char 数组,强转inotify_event 后判断mask 打印name 信息。
提示
针对文件描述符fd调用
ioctl(fd, FIONREAD, &numbytes)
,会返回其所指代的inotify实例中的当前可读字节数。在非阻塞模式或阻塞模式 read(...) 前可以提前调用一下,看看有没有数据可读...
示例
#include <sys/inotify.h>
#include <err.h>
#include <unistd.h>
#include <limits.h>
#include <stdio.h>
typedef struct inotify_event inotify_event;
int main (void)
{
const char dir[] = "/home/watchdir";
int fd_notify = inotify_init();
if (inotify_add_watch (fd_notify, dir, IN_CREATE | IN_DELETE) == -1)
err (-1, "inotify_add_watch() %d", __LINE__);
char buf[sizeof (inotify_event) + NAME_MAX + 1];
for (; ;) {
ssize_t nread = read (fd_notify, buf, sizeof (buf));
inotify_event *event = (inotify_event *) buf;
if (event->mask & IN_CREATE)
printf ("new file <%s> is created in <%s>\n", event->name, dir);
else if (event->mask & IN_DELETE)
printf ("file <%s> is removed\n", event->name);
}
}
注意事项
- inotify无法检测
/proc
、/sys
等伪文件。 - 当你希望使用 inotify 来监视某一个文件的创建和删除时,因为inotify 无法监视一个不存在的文件,你应该使用监视文件所在目录的方式来监听。
- inofity 的句柄文件描述符和普通的文件描述符一样,你可以使用epoll 来监听inotify 句柄的读事件来高效的响应文件的变动事件。