# 10.6 读取文件元数据

应用程序能够通过调用 stat 和 fstat 函数，检索到关于文件的信息（有时也称为文件的**元数据**（metadata））。

```c
#include <unistd.h>
#include <sys/stat.h>

int stat(const char *filename, struct stat *buf);
int fstat(int fd, struct stat *buf);

// 返回：若成功则为 0，若出错则为 -1。
```

stat 函数以一个文件名作为输入，并填写如图 10-9 所示的一个 stat 数据结构中的各个成员。fstat 函数是相似的，只不过是以文件描述符而不是文件名作为输入。当我们在 11.5 节中讨论 Web 服务器时，会需要 stat 数据结构中的 st\_mode 和 st\_size 成员，其他成员则不在我们的讨论之列。

{% tabs %}
{% tab title="statbuf.h (included by sys/stat.h)" %}

```c
/* Metadata returned by the stat and fstat functions */
struct stat {
    dev_t         st_dev;      /* Device */
    ino_t         st_ino;      /* inode */
    mode_t        st_mode;     /* Protection and file type */
    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 type (if inode device) */
    off_t         st_size;     /* Total size, in bytes */
    unsigned long st_blksize;  /* Block size for filesystem I/O */
    unsigned long st_blocks;   /* Number of 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 change */
};
```

{% endtab %}
{% endtabs %}

> 图 10-9 stat 数据结构

st\_size 成员包含了文件的字节数大小。st\_mode 成员则编码了文件访问许可位（图 10-2）和文件类型（10.2 节）。Linux 在 sys/stat.h 中定义了宏谓词来确定 st\_mode 成员的文件类型：

* **S\_ISREG(m)**。这是一个普通文件吗？
* **S\_ISDIR(m)**。这是一个目录文件吗？
* **S\_ISSOCK(m)**。这是一个网络套接字吗？

图 10-10 展示了我们会如何使用这些宏和 stat 函数来读取和解释一个文件的 st\_mode 位。

{% tabs %}
{% tab title="code/io/statcheck.c" %}

```c
#include "csapp.h"

int main (int argc, char **argv)
{
    struct stat stat;
    char *type, *readok;

    Stat(argv[1], &stat);
    if (S_ISREG(stat.st_mode))     /* Determine file type */
        type = "regular";
    else if (S_ISDIR(stat.st_mode))
        type = "directory";
    else
        type = "other";
    if ((stat.st_mode & S_IRUSR))  /* Check read access */
        readok = "yes";
    else
        readok = "no";

    printf("type: %s, read: %s\n", type, readok);
    exit(0);
}
```

{% endtab %}
{% endtabs %}

> 图 10-10 查询和处理一个文件的 st\_mode 位


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://hansimov.gitbook.io/csapp/part3/ch10-system-level-io/10.6-reading-file-metadata.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
