structstat详解

发布时间:2023-05-18

一、struct stat 概述

struct stat 是一个 C 语言中的结构体,它包含了 Unix 和类 Unix 系统中文件状态的所有信息。struct stat 用于查询文件的各种属性信息,比如大小、权限、时间戳等。在 Unix 和类 Unix 系统中,struct stat 结构体十分常见和有用。 stat 系统调用是 Unix 和类 Unix 系统中最常用的系统调用之一。它用于获取文件的元数据,并将其存储在 struct stat 结构体中。元数据包括文件类型、大小、属性、访问时间、修改时间等。struct stat 结构体定义如下:

struct stat {
  dev_t     st_dev;         /* ID of device containing file */
  ino_t     st_ino;         /* Inode number */
  mode_t    st_mode;        /* File type and mode */
  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 512B 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 status change */
};

我们可以通过 Manipulating File AttributesStat() 两篇官方文档了解如何使用 struct stat 获取文件信息。

二、使用 StructStatVfs 获取文件系统信息

struct stat 不仅可以用于获取文件的属性信息,还可以用于获取文件系统的相关信息。可以使用下面列出的函数来获取完全的 stat 结构,也可以使用较简单的基本信息函数(如 st_sizest_mtime 等)来获取部分信息。

1. statvfs()

statvfs() 函数是一个 Unix 系统调用,用于检索文件系统的状态(特别是容量)。它返回一个 struct statvfs 结构体,其中包含文件系统的各种信息。struct statvfs 定义如下:

struct statvfs {
  unsigned long  f_bsize;    /* file system block size */
  unsigned long  f_frsize;   /* fragment size */
  fsblkcnt_t     f_blocks;   /* size of fs in f_frsize units */
  fsblkcnt_t     f_bfree;    /* free blocks in fs */
  fsblkcnt_t     f_bavail;   /* free blocks avail to non-superuser */
  fsfilcnt_t     f_files;    /* total file nodes in file system */
  fsfilcnt_t     f_ffree;    /* free file nodes in fs */
  fsfilcnt_t     f_favail;   /* free file nodes avail to non-superuser */
  unsigned long  f_fsid;     /* file system id */
  unsigned long  f_flag;     /* mount flags */
  unsigned long  f_namemax;  /* maximum filename length */
};

我们可以使用下面这个使用案例看一下如何使用 statvfs() 函数,使用该函数返回当前文件系统(root 文件系统)的容量信息。

#include <stdio.h>
#include <sys/statvfs.h>
int main() {
    struct statvfs stats;
    statvfs("/", &stats);
    printf("File system block size: %ld\n", stats.f_bsize);
    printf("Fragment size: %ld\n", stats.f_frsize);
    printf("Total blocks (in f_frsize units): %ld\n", stats.f_blocks);
    printf("Free blocks available to non-superuser: %ld\n", stats.f_bavail);
    printf("Total file nodes (in f_frsize units): %ld\n", stats.f_files);
    printf("Free file nodes (in f_frsize units): %ld\n", stats.f_ffree);
    printf("Max filename length: %ld\n", stats.f_namemax);
    return 0;
}

2. fstatvfs()

fstatvfs() 函数也是用于检索文件系统的状态(特别是容量)。它和 statvfs() 函数的用法几乎一模一样,只是它使用的是文件描述符(fd)来代替文件名。我们可以使用下面这个使用案例看一下如何使用 fstatvfs() 函数,使用该函数返回当前进程所在文件系统的容量信息。

#include <stdio.h>
#include <sys/statvfs.h>
#include <unistd.h>
int main() {
    int fd;
    struct statvfs stats;
    fd = open(".", O_RDONLY);
    fstatvfs(fd, &stats);
    close(fd);
    printf("File system block size: %ld\n", stats.f_bsize);
    printf("Fragment size: %ld\n", stats.f_frsize);
    printf("Total blocks (in f_frsize units): %ld\n", stats.f_blocks);
    printf("Free blocks available to non-superuser: %ld\n", stats.f_bavail);
    printf("Total file nodes (in f_frsize units): %ld\n", stats.f_files);
    printf("Free file nodes (in f_frsize units): %ld\n", stats.f_ffree);
    printf("Max filename length: %ld\n", stats.f_namemax);
    return 0;
}

三、使用 StructStat 获取文件信息

我们可以使用下面列出的使用案例来获取文件的信息:

#include <stdio.h>
#include <sys/stat.h>
int main() {
    struct stat sb;
    if (stat("/etc/passwd", &sb) == -1) {
        perror("stat");
        return 1;
    }
    printf("File type:        ");
    switch (sb.st_mode & S_IFMT) {
        case S_IFBLK:  printf("block device\n");            break;
        case S_IFCHR:  printf("character device\n");        break;
        case S_IFDIR:  printf("directory\n");               break;
        case S_IFIFO:  printf("FIFO/pipe\n");               break;
        case S_IFLNK:  printf("symlink\n");                 break;
        case S_IFREG:  printf("regular file\n");            break;
        case S_IFSOCK: printf("socket\n");                  break;
        default:       printf("unknown?\n");                break;
    }
    printf("I-node number:    %ld\n", (long) sb.st_ino);
    printf("Mode:             %lo (octal)\n",
            (unsigned long) sb.st_mode);
    printf("Link count:       %ld\n", (long) sb.st_nlink);
    printf("Ownership:        UID=%ld   GID=%ld\n",
            (long) sb.st_uid, (long) sb.st_gid);
    printf("Preferred I/O block size: %ld bytes\n",
            (long) sb.st_blksize);
    printf("File size:        %lld bytes\n",
            (long long) sb.st_size);
    printf("Blocks allocated: %lld\n",
            (long long) sb.st_blocks);
    printf("Last status change:       %s", ctime(&sb.st_ctime));
    printf("Last file access:         %s", ctime(&sb.st_atime));
    printf("Last file modification:   %s", ctime(&sb.st_mtime));
    return 0;
}

四、使用 StructStat 在 Windows 系统中获取文件信息

在 Windows 系统中,我们可以使用下面列出的使用案例来获取文件的信息:

#include <windows.h>
#include <stdio.h>
#include <sys/stat.h>
int main() {
    struct _stat buffer;
    int status;
    status = _stat("C:\\file.txt", &buffer);
    if (status == 0) {
        printf("File size:         %ld bytes\n", buffer.st_size);
        printf("Creation date:     %s", ctime(&buffer.st_ctime));
        printf("Modification date: %s", ctime(&buffer.st_mtime));
        printf("Access date:       %s", ctime(&buffer.st_atime));
    } else {
        printf("File not found");
    }
    return 0;
}

五、使用 StructStat 在 MacOS 系统中获取文件信息

在 MacOS 系统中,我们可以使用下面的使用案例来获取文件的信息:

#include <sys/stat.h>
#include <errno.h>
#include <stdio.h>
#include <unistd.h>
int main() {
    struct stat statbuf;
    if (stat("/etc/passwd", &statbuf) == -1) {
        perror("stat");
        return -1;
    }
    printf("Size: %lld\n", statbuf.st_size);
    printf("User ID: %d\n", statbuf.st_uid);
    printf("Group ID: %d\n", statbuf.st_gid);
    return 0;
}

六、小结

利用 struct stat 结构体可以轻松地获取到文件系统和文件的各种属性信息,可以方便地实现类 Unix 操作系统在使用过程中的代码控制。