stat 函数族介绍
程序员文章站
2022-07-10 22:25:33
...
stat 函数族可以用来获取文件的结构元信息,主要有以下四个函数:
其中,stat 函数获得与 pathname 命名文件有关的信息结构;fstat 函数获得已在描述符 fd 上打开文件的有关信息;lstat 函数类似于 stat,但当命名文件是一个符号链接时,则获取的是该符号链接的有关信息,而非引用文件的信息。
fstatat 函数为一个相对于当前打开目录(由 fd 参数指向)的路径名返回文件统计信息。flag 参数控制着是否跟随着一个符号链接。当设置 AT_SYMLINK_NOFOLLOW 标志时,fstatat 函数不会跟随符号链接,而是返回符号链接本身的信息。否则,在默认情况下,返回的是符号链接所指向的实际文件的信息。如果 fd 参数的值是 AT_FDCWD,并且 pathname 是一个相对路径名,
fstatat 会计算相对于当前目录的 pathname 参数。如果 pathname 是一个绝对路径,fd 参数就会被忽略。这两种情况下,根据 flag 的取值,fstatat 的作用就跟 stat 或 lstat 一样。
另一个参数 buf 是一个 stat 结构地址,stat 函数族会在调用时自动填充该结构的内容。结构的实际定义可能随具体实现有所不同,但其基本形式是:
timespec 结构类型按照秒和纳秒定义了时间,至少包括下面两个字段:
time_t tv_sec;
long tv_nsec;
stat 结构中的 st_mode 包含了文件类型信息,文件类型包括如下几种:
(1) 普通文件(regular file)。这是最常用的文件类型,包含了某种形式的数据。至于是文本还是二进制数据,UNIX 内核并不在意,因为对普通文件内容的解释是由该文件的应用程序进行的。不过一个值得注意的例外是二进制可执行文件。为了执行程序,内核必须理解其格式。所有二进制可执行文件都遵循一种标准化的格式,以便内核能够确定程序文本和数据的加载位置。
(2) 目录文件(directory file)。这种文件包含了其他文件的名字以及指向与这些文件信息有关的指针。对一个目录具有读权限的任意进程都可以读该目录的内容,但只有内核可以直接写目录文件,进程必须使用特定的函数才能更改目录。
(3) 块特殊文件(block special file)(注意,FreeBSD 不再支持块特殊文件,对设备的所有访问需要通过字符特殊文件进行)。这种类型的文件提供对设备(如磁盘)带缓冲的访问,每次访问以固定长度为单位进行。
(4) 字符特殊文件(character special file)。这种类型的文件提供对设备不带缓冲的访问,每次访问长度可变。系统中的所有设备要么是字符特殊文件,要么是块特殊文件。
(5) FIFO。这种类型的文件用于进程间通信,有时也称命名管道(named pipe)。
(6) 套接字(socket)。这种类型的文件用于进程间的网络通信,也可以用于一台宿主机上进程间的非网络通信。
(7) 符号链接(symbolic link)。这种类型的文件指向另一个文件。
可以用下面这些宏来确定文件类型,这些宏的参数都是 stat 结构中的 st_mode 成员:
另外,POSIX.1 允许实现将进程间通信(IPC)对象(如消息队列和信号量等)说明为文件。下面这些宏可用来从 stat 结构中确定 IPC 对象的类型,它们的参数是指向 stat 结构的指针:
下面是一个查看文件类型的示例:
运行结果:
#include <sys/stat.h> int stat(const char *restrict pathname, struct stat *restrict buf); int fstat(int fd, struct stat *buf); int lstat(const char *restrict pathname, struct stat *restrict buf); int fstatat(int fd,const char *restrict pathname,struct stat *restrict buf,int flag); /* 四个函数的返回值:若成功,返回 0;否则,返回 -1 */
其中,stat 函数获得与 pathname 命名文件有关的信息结构;fstat 函数获得已在描述符 fd 上打开文件的有关信息;lstat 函数类似于 stat,但当命名文件是一个符号链接时,则获取的是该符号链接的有关信息,而非引用文件的信息。
fstatat 函数为一个相对于当前打开目录(由 fd 参数指向)的路径名返回文件统计信息。flag 参数控制着是否跟随着一个符号链接。当设置 AT_SYMLINK_NOFOLLOW 标志时,fstatat 函数不会跟随符号链接,而是返回符号链接本身的信息。否则,在默认情况下,返回的是符号链接所指向的实际文件的信息。如果 fd 参数的值是 AT_FDCWD,并且 pathname 是一个相对路径名,
fstatat 会计算相对于当前目录的 pathname 参数。如果 pathname 是一个绝对路径,fd 参数就会被忽略。这两种情况下,根据 flag 的取值,fstatat 的作用就跟 stat 或 lstat 一样。
另一个参数 buf 是一个 stat 结构地址,stat 函数族会在调用时自动填充该结构的内容。结构的实际定义可能随具体实现有所不同,但其基本形式是:
struct stat{ mode_t st_mode; // file type & mode (permissions) ino_t st_ino; // i-node number (serial number) dev_t st_dev; // device number (file system) dev_t st_rdev; // device number for special files (XSI) nlink_t st_nlink; // number of links uid_t st_uid; // user ID of owner gid_t st_gid; // group ID of owner off_t st_size; // size in bytes, for regular files struct timespec st_atim; // time of last access struct timespec st_mtim; // time of last modification struct timespec st_ctim; // time of last file status change blksize_t st_blksize; // best I/O block size (XSI) blkcnt_t st_blocks; // number of disk blocks allocated (XSI) };
timespec 结构类型按照秒和纳秒定义了时间,至少包括下面两个字段:
time_t tv_sec;
long tv_nsec;
stat 结构中的 st_mode 包含了文件类型信息,文件类型包括如下几种:
(1) 普通文件(regular file)。这是最常用的文件类型,包含了某种形式的数据。至于是文本还是二进制数据,UNIX 内核并不在意,因为对普通文件内容的解释是由该文件的应用程序进行的。不过一个值得注意的例外是二进制可执行文件。为了执行程序,内核必须理解其格式。所有二进制可执行文件都遵循一种标准化的格式,以便内核能够确定程序文本和数据的加载位置。
(2) 目录文件(directory file)。这种文件包含了其他文件的名字以及指向与这些文件信息有关的指针。对一个目录具有读权限的任意进程都可以读该目录的内容,但只有内核可以直接写目录文件,进程必须使用特定的函数才能更改目录。
(3) 块特殊文件(block special file)(注意,FreeBSD 不再支持块特殊文件,对设备的所有访问需要通过字符特殊文件进行)。这种类型的文件提供对设备(如磁盘)带缓冲的访问,每次访问以固定长度为单位进行。
(4) 字符特殊文件(character special file)。这种类型的文件提供对设备不带缓冲的访问,每次访问长度可变。系统中的所有设备要么是字符特殊文件,要么是块特殊文件。
(5) FIFO。这种类型的文件用于进程间通信,有时也称命名管道(named pipe)。
(6) 套接字(socket)。这种类型的文件用于进程间的网络通信,也可以用于一台宿主机上进程间的非网络通信。
(7) 符号链接(symbolic link)。这种类型的文件指向另一个文件。
可以用下面这些宏来确定文件类型,这些宏的参数都是 stat 结构中的 st_mode 成员:
#include <sys/stat.h> S_ISREG() // 普通文件 S_ISDIR() // 目录文件 S_ISCHR() // 字符特殊文件 S_ISBLK() // 块特殊文件 S_ISFIFO() // 管道或 FIFO S_ISLNK() // 符号链接 S_ISSOCK() // 套接字
另外,POSIX.1 允许实现将进程间通信(IPC)对象(如消息队列和信号量等)说明为文件。下面这些宏可用来从 stat 结构中确定 IPC 对象的类型,它们的参数是指向 stat 结构的指针:
#include <sys/stat.h> S_TYPEISMQ() // 消息队列 S_TYPEISSEM() // 信号量 S_TYPEISSHM() // 共享存储对象
下面是一个查看文件类型的示例:
#include <stdio.h> #include <stdlib.h> #include <sys/stat.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\n"); 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); }
运行结果:
$ ./printFileType.out /etc/passwd /etc /dev/log /dev/tty /var/lib/oprofile/opd_pipe /dev/sr0 /dev/cdrom /etc/passwd: regular /etc: directory /dev/log: socket /dev/tty: character special /var/lib/oprofile/opd_pipe: lstat error /dev/sr0: block special /dev/cdrom: symbolic link