Linux C语言stat函数如何获取文件状态信息?

99ANYc3cd6
预计阅读时长 25 分钟
位置: 首页 C语言 正文

stat 是一个非常重要的系统调用,它用于获取文件或文件系统的状态信息,通过 stat,你的程序可以知道一个文件的大小、权限、所有者、最后修改时间等各种属性。

linux c语言stat
(图片来源网络,侵删)

核心概念

stat 函数通过一个指向 stat 结构体的指针来返回文件信息,你需要做的是:

  1. 包含头文件: sys/stat.hunistd.h
  2. 定义 stat 结构体变量: struct stat file_stat;
  3. 调用 stat 函数: 将文件路径和结构体变量的地址传给它。
  4. 检查返回值: 如果函数返回 0,表示成功;返回 -1 表示失败,此时可以通过 errno 变量查看具体错误原因。
  5. 访问结构体成员: 成功后,文件的所有信息都存储在 file_stat 变量中,你可以通过它的成员来获取。

函数原型

#include <sys/stat.h>
#include <unistd.h> // 包含了 ssize_t 等类型定义
int stat(const char *pathname, struct stat *statbuf);

参数:

  • pathname: 要查询的文件的路径名,可以是相对路径或绝对路径。
  • statbuf: 指向 struct stat 结构体的指针。stat 函数会将文件信息填充到这个结构体中。

返回值:

  • 成功: 返回 0
  • 失败: 返回 -1,并设置 errno 来指示错误。

stat 结构体详解

struct stat 是核心,它定义了文件的各种属性,以下是其主要成员(在 64 位系统上,通常以 64st_mode_t):

linux c语言stat
(图片来源网络,侵删)
struct stat {
    dev_t     st_dev;     // 文件的设备 ID
    ino_t     st_ino;     // inode 号
    mode_t    st_mode;    // 文件类型和权限 ( S_IFREG | 0644)
    nlink_t   st_nlink;   // 硬链接数
    uid_t     st_uid;     // 用户 ID
    gid_t     st_gid;     // 组 ID
    dev_t     st_rdev;    // 设备 ID (如果是特殊文件)
    off_t     st_size;    // 文件大小(字节),以字节为单位
    blksize_t st_blksize; // 文件系统 I/O 的块大小
    blkcnt_t  st_blocks;  // 分配的 512 字节块的数量
    time_t    st_atime;   // 最后访问时间 (access time)
    time_t    st_mtime;   // 最后修改内容的时间 (modification time)
    time_t    st_ctime;   // 最后状态改变的时间 (status change time)
};

关键成员解释:

  • st_mode: 这是一个非常重要的成员,它包含了文件的类型和权限,我们可以用宏来解析它:

    • 文件类型:
      • S_ISREG(m): 是否是普通文件
      • S_ISDIR(m): 是否是目录
      • S_ISLNK(m): 是否是符号链接
      • S_ISBLK(m): 是否是块设备文件
      • S_ISCHR(m): 是否是字符设备文件
      • S_ISFIFO(m): 是否是命名管道 (FIFO)
      • S_ISSOCK(m): 是否是套接字 (socket)
    • 文件权限:
      • S_IRUSR (用户读), S_IWUSR (用户写), S_IXUSR (用户执行)
      • S_IRGRP (组读), S_IWGRP (组写), S_IXGRP (组执行)
      • S_IROTH (其他读), S_IWOTH (其他写), S_IXOTH (其他执行)
      • st_mode & 0777 可以提取出文件的权限位(如 0644)。
  • st_size: 文件的大小(字节),对于目录,这个值通常没有太大意义。

  • st_uid, st_gid: 文件所有者和所属组的 ID,通常需要结合 <sys/types.h><pwd.h>/<grp.h> 中的函数 getpwuid()getgrgid() 来转换成可读的用户名和组名。

    linux c语言stat
    (图片来源网络,侵删)
  • st_atime, st_mtime, st_ctime: 三个时间戳。

    • st_atime: Access Time,最后一次访问(读取)文件的时间,用 cat 命令查看文件内容,atime 就会更新。
    • st_mtime: Modification Time,最后一次修改文件内容的时间,用 echovim 编辑文件,mtime 就会更新,这是最常用的时间戳。
    • st_ctime: Change Time,最后一次改变文件状态(如权限、所有者)或 inode 内容的时间,用 chmodchown 命令,ctime 就会更新。

完整示例代码

下面是一个完整的示例,它会打印出指定文件的几乎所有 stat 信息。

#include <stdio.h>
#include <sys/stat.h>
#include <unistd.h>
#include <time.h>
#include <errno.h>
#include <pwd.h>      // 用于 getpwuid
#include <grp.h>      // 用于 getgrgid
#include <stdlib.h>   // 用于 exit
// 辅助函数:将 st_mode 转换为可读的权限字符串 (如 rwxr-xr--)
void print_permissions(mode_t mode) {
    printf((mode & S_IRUSR) ? "r" : "-");
    printf((mode & S_IWUSR) ? "w" : "-");
    printf((mode & S_IXUSR) ? "x" : "-");
    printf((mode & S_IRGRP) ? "r" : "-");
    printf((mode & S_IWGRP) ? "w" : "-");
    printf((mode & S_IXGRP) ? "x" : "-");
    printf((mode & S_IROTH) ? "r" : "-");
    printf((mode & S_IWOTH) ? "w" : "-");
    printf((mode & S_IXOTH) ? "x" : "-");
}
// 辅助函数:将 st_mode 转换为文件类型字符串
void print_file_type(mode_t mode) {
    if (S_ISREG(mode)) printf("普通文件");
    else if (S_ISDIR(mode)) printf("目录");
    else if (S_ISLNK(mode)) printf("符号链接");
    else if (S_ISBLK(mode)) printf("块设备");
    else if (S_ISCHR(mode)) printf("字符设备");
    else if (S_ISFIFO(mode)) printf("FIFO/命名管道");
    else if (S_ISSOCK(mode)) printf("套接字");
    else printf("未知类型");
}
int main(int argc, char *argv[]) {
    if (argc != 2) {
        fprintf(stderr, "用法: %s <文件路径>\n", argv[0]);
        return 1;
    }
    const char *filepath = argv[1];
    struct stat file_stat;
    // 调用 stat 函数
    if (stat(filepath, &file_stat) == -1) {
        // 打印错误信息
        perror("stat 调用失败");
        return 1;
    }
    // 打印文件信息
    printf("文件: %s\n", filepath);
    printf("----------------------------------------\n");
    printf("设备 ID: %ld\n", (long)file_stat.st_dev);
    printf("inode 号: %ld\n", (long)file_stat.st_ino);
    printf("类型: ");
    print_file_type(file_stat.st_mode);
    printf("\n");
    printf("权限: ");
    print_permissions(file_stat.st_mode);
    printf("\n");
    printf("硬链接数: %ld\n", (long)file_stat.st_nlink);
    // 获取用户名和组名
    struct passwd *pw = getpwuid(file_stat.st_uid);
    struct group *gr = getgrgid(file_stat.st_gid);
    printf("所有者: %s (ID: %d)\n", pw ? pw->pw_name : "未知", file_stat.st_uid);
    printf("所属组: %s (ID: %d)\n", gr ? gr->gr_name : "未知", file_stat.st_gid);
    printf("文件大小: %ld 字节\n", (long)file_stat.st_size);
    printf("块大小: %ld 字节\n", (long)file_stat.st_blksize);
    printf("块数量: %ld\n", (long)file_stat.st_blocks);
    // 打印时间戳
    char time_buf[80];
    printf("最后访问时间: %s", ctime(&file_stat.st_atime));
    printf("最后修改时间: %s", ctime(&file_stat.st_mtime));
    printf("最后状态改变时间: %s", ctime(&file_stat.st_ctime));
    return 0;
}

如何编译和运行:

  1. 将上述代码保存为 file_stat.c
  2. 创建一个测试文件 test.txt 并写入一些内容:
    echo "Hello, stat function!" > test.txt
    chmod 644 test.txt
  3. 编译代码:
    gcc file_stat.c -o file_stat
  4. 运行程序:
    ./file_stat test.txt

预期输出示例:

文件: test.txt
----------------------------------------
设备 ID: 2050
inode 号: 131073
类型: 普通文件
权限: rw-r--r--
硬链接数: 1
所有者: your_username (ID: 1000)
所属组: your_group (ID: 1000)
文件大小: 21 字节
块大小: 4096 字节
块数量: 8
最后访问时间: Wed Oct 26 10:30:00 2025
最后修改时间: Wed Oct 26 10:30:00 2025
最后状态改变时间: Wed Oct 26 10:30:00 2025

statlstatfstat 的区别

在 Linux 中,有三个非常相似的函数,理解它们的区别很重要:

函数 描述 区别
stat() 获取文件路径指向的最终目标文件的信息。 如果路径是符号链接,它会解引用(dereference),获取链接所指向的文件的信息。
lstat() 获取文件路径本身(符号链接文件)的信息。 如果路径是符号链接,它不会解引用,而是获取这个链接文件本身的信息(比如链接本身的大小),这是它与 stat 的关键区别。
fstat() 获取一个已打开的文件描述符 (fd) 所对应的文件的信息。 它不使用文件路径,而是使用由 open()creat() 等函数返回的文件描述符。

lstat 示例:

假设你有一个符号链接 mylink.txt 指向 test.txt

ln -s test.txt mylink.txt

stat 查看 mylink.txt:

stat("mylink.txt", &stat_buf); // 会获取 test.txt 的信息

lstat 查看 mylink.txt:

lstat("mylink.txt", &stat_buf); // 会获取 mylink.txt 这个链接文件本身的信息
                                  // st_size 会很小,8 (因为 "test.txt" 是 8 个字符)
  • stat 是获取文件状态信息的基石。
  • 它的核心是 struct stat 结构体,你需要熟练掌握其主要成员的含义。
  • st_mode 中的宏(S_ISREG, S_IRUSR 等)是解析文件类型和权限的关键。
  • 当处理符号链接时,请务必使用 lstat 来获取链接本身的信息,避免意外的解引用。
-- 展开阅读全文 --
头像
织梦提速有哪些实用技巧?
« 上一篇 今天
dede 图片集 可选
下一篇 » 今天

相关文章

取消
微信二维码
支付宝二维码

目录[+]