首页 元宇宙

C 语言进阶:UNIX 文件属性获取与 stat 结构、localtime 函数详解

分类:元宇宙
字数: (6880)
阅读: (2672)
内容摘要:C 语言进阶:UNIX 文件属性获取与 stat 结构、localtime 函数详解,

在 UNIX 系统下进行 C 语言编程时,经常需要获取文件的各种属性,例如文件大小、创建时间、修改时间、访问权限等。stat 结构体和 localtime 函数是完成这项任务的关键工具。本文将深入探讨如何使用它们,并结合实际案例分析常见的坑。

stat 结构体

stat 结构体定义在 <sys/stat.h> 头文件中,用于存储文件的各种元数据。 使用 stat()fstat()lstat() 函数可以填充这个结构体。以下是 stat 结构体的常见成员:

  • st_dev: 设备ID
  • st_ino: inode number
  • st_mode: 文件类型和权限
  • st_nlink: 链接数
  • st_uid: 用户ID
  • st_gid: 组ID
  • st_rdev: 特殊设备ID (只用于设备文件)
  • st_size: 文件大小 (字节)
  • st_atime: 最后访问时间
  • st_mtime: 最后修改时间
  • st_ctime: 最后状态改变时间
  • st_blksize: 文件系统 I/O 的最佳块大小
  • st_blocks: 分配的块数

stat()fstat()lstat() 函数

  • stat(const char *path, struct stat *buf):根据文件路径获取文件属性,并将结果存储在 buf 指向的 stat 结构体中。
  • fstat(int fd, struct stat *buf):根据文件描述符获取文件属性,并将结果存储在 buf 指向的 stat 结构体中。
  • lstat(const char *path, struct stat *buf):与 stat() 类似,但如果文件是一个符号链接,lstat() 获取的是符号链接本身的属性,而不是它指向的文件的属性。

localtime() 函数

stat 结构体中的时间成员(st_atimest_mtimest_ctime)存储的是自 Epoch (1970-01-01 00:00:00 +0000 UTC) 以来经过的秒数。为了将其转换为可读的本地时间,需要使用 localtime() 函数。localtime() 函数将 time_t 类型的时间值转换为 struct tm 类型的本地时间。

C 语言进阶:UNIX 文件属性获取与 stat 结构、localtime 函数详解

代码示例

#include <stdio.h>
#include <sys/stat.h>
#include <time.h>

int main() {
    struct stat file_stat;
    const char *filename = "test.txt";

    if (stat(filename, &file_stat) == 0) {
        printf("File size: %ld bytes\n", file_stat.st_size);

        // 获取最后修改时间
        time_t last_modified_time = file_stat.st_mtime;
        struct tm *time_info = localtime(&last_modified_time);

        // 格式化时间输出
        char time_buffer[80];
        strftime(time_buffer, sizeof(time_buffer), "%Y-%m-%d %H:%M:%S", time_info);
        printf("Last modified: %s\n", time_buffer);

        // 判断文件类型
        if (S_ISREG(file_stat.st_mode)) {
            printf("%s is a regular file.\n", filename);
        } else if (S_ISDIR(file_stat.st_mode)) {
            printf("%s is a directory.\n", filename);
        } else {
            printf("%s is another type of file.\n", filename);
        }
    } else {
        perror("stat"); // 输出错误信息
        return 1;
    }

    return 0;
}

实战避坑经验总结

  1. 符号链接处理:如果需要获取符号链接指向的文件的属性,应该使用 stat()。如果需要获取符号链接本身的属性,则使用 lstat()
  2. 错误处理stat()fstat()lstat() 函数在出错时返回 -1,并设置 errno。务必检查返回值并使用 perror() 输出错误信息,方便调试。
  3. 线程安全localtime() 函数不是线程安全的,因为它使用静态缓冲区。在多线程程序中,应该使用 localtime_r() 函数,它需要一个额外的参数来存储结果,从而避免线程安全问题。
  4. 时区问题localtime() 函数返回的是本地时间。如果需要获取 UTC 时间,可以使用 gmtime() 函数。
  5. 文件权限判断st_mode 成员包含了文件类型和权限信息。可以使用 S_ISREG()S_ISDIR() 等宏来判断文件类型,使用位运算来检查文件权限。例如,可以使用 file_stat.st_mode & S_IRUSR 来判断文件所有者是否有读权限。在处理 Nginx 日志分析或者权限控制的场景,这些技巧非常有用。

理解并熟练运用 stat 结构体和 localtime 函数,能够帮助我们更好地进行 UNIX 系统下的 C 语言编程,编写出更加健壮和可靠的程序。 这对于编写高性能的服务器程序,比如高并发连接的 Nginx 模块开发,以及构建可靠的反向代理和负载均衡系统至关重要。

UNIX 文件其他属性获取:权限与用户

除了文件大小和时间,UNIX 文件还有权限和所有者等重要属性。 利用 stat 结构体,可以方便地获取和修改这些属性。理解这些属性对于系统安全和文件管理至关重要。 常见的应用场景包括:

C 语言进阶:UNIX 文件属性获取与 stat 结构、localtime 函数详解
  • 访问控制:根据用户身份和文件权限,决定是否允许用户访问文件。
  • 日志审计:记录文件的访问和修改情况,用于安全审计。
  • 自动化脚本:编写脚本自动管理文件权限和所有者。

文件权限表示

UNIX 文件权限使用 9 个比特位来表示,分为三组,分别代表文件所有者 (user)、所属组 (group) 和其他用户 (others) 的权限。每组权限包含读 (read)、写 (write) 和执行 (execute) 三种权限。 这些权限在 stat 结构体的 st_mode 成员中以位掩码的形式存在。

常见的权限宏定义如下:

C 语言进阶:UNIX 文件属性获取与 stat 结构、localtime 函数详解
  • S_IRUSR: 文件所有者读权限
  • S_IWUSR: 文件所有者写权限
  • S_IXUSR: 文件所有者执行权限
  • S_IRGRP: 所属组读权限
  • S_IWGRP: 所属组写权限
  • S_IXGRP: 所属组执行权限
  • S_IROTH: 其他用户读权限
  • S_IWOTH: 其他用户写权限
  • S_IXOTH: 其他用户执行权限

获取文件所有者信息

stat 结构体的 st_uid 成员表示文件所有者的用户 ID (UID),st_gid 成员表示文件所属组的组 ID (GID)。可以通过 getpwuid()getgrgid() 函数,根据 UID 和 GID 获取用户和组的详细信息。

#include <stdio.h>
#include <sys/stat.h>
#include <pwd.h>
#include <grp.h>

int main() {
    struct stat file_stat;
    const char *filename = "test.txt";

    if (stat(filename, &file_stat) == 0) {
        // 获取用户和组信息
        struct passwd *user_info = getpwuid(file_stat.st_uid);
        struct group *group_info = getgrgid(file_stat.st_gid);

        if (user_info != NULL) {
            printf("Owner: %s (%d)\n", user_info->pw_name, file_stat.st_uid);
        } else {
            printf("Owner UID: %d\n", file_stat.st_uid);
        }

        if (group_info != NULL) {
            printf("Group: %s (%d)\n", group_info->gr_name, file_stat.st_gid);
        } else {
            printf("Group GID: %d\n", file_stat.st_gid);
        }
    } else {
        perror("stat");
        return 1;
    }

    return 0;
}

修改文件权限和所有者

可以使用 chmod() 函数修改文件权限,使用 chown() 函数修改文件所有者,使用 chgrp() 函数修改文件所属组。 但是,修改文件权限和所有者需要相应的权限。

C 语言进阶:UNIX 文件属性获取与 stat 结构、localtime 函数详解
#include <stdio.h>
#include <sys/stat.h>
#include <unistd.h>

int main() {
    const char *filename = "test.txt";
    mode_t new_permissions = 0644; // 八进制表示,等价于 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH
    uid_t new_owner = 1000; // 用户 ID
    gid_t new_group = 1000; // 组 ID

    // 修改文件权限
    if (chmod(filename, new_permissions) == 0) {
        printf("Permissions changed successfully.\n");
    } else {
        perror("chmod");
    }

    // 修改文件所有者和组
    if (chown(filename, new_owner, new_group) == 0) {
        printf("Owner and group changed successfully.\n");
    } else {
        perror("chown");
    }

    return 0;
}

在实际应用中,需要根据具体需求灵活使用这些函数。 例如,在 Web 服务器中,可能需要定期检查网站文件的权限,确保只有授权用户才能访问和修改这些文件。 对于使用宝塔面板管理服务器的用户,这些底层操作由面板封装,但理解背后的原理仍然十分重要。

C 语言进阶:UNIX 文件属性获取与 stat 结构、localtime 函数详解

转载请注明出处: 青衫落拓

本文的链接地址: http://m.acea2.store/blog/649880.SHTML

本文最后 发布于2026-04-22 21:50:44,已经过了4天没有更新,若内容或图片 失效,请留言反馈

()
您可能对以下文章感兴趣
评论
  • 兰州拉面 1 天前
    有没有关于文件硬链接和软链接的讲解?
  • 柚子很甜 4 天前
    写得真好!stat 结构体这块一直有点模糊,这下彻底搞明白了。