# 10.1 Unix I/O

一个 Linux 文件就是一个 m 个字节的序列：

$$
B\_0,B\_1,\cdots,B\_k,\cdots,B\_{m-1}
$$

所有的 I/O 设备（例如网络、磁盘和终端）都被模型化为文件，而所有的输入和输出都被当作对相应文件的读和写来执行。这种将设备优雅地映射为文件的方式，允许 Linux 内核引出一个简单、低级的应用接口，称为 Unix I/O，这使得所有的输入和输出都能以一种统一且一致的方式来执行：

* **打开文件。**&#x4E00;个应用程序通过要求内核打开相应的文件，来宣告它想要访问一个 I/O 设备。内核返回一个小的非负整数，叫做描述符，它在后续对此文件的所有操作中标识这个文件。内核记录有关这个打开文件的所有信息。应用程序只需记住这个描述符。
* Linux shell 创建的每个进程开始时都有三个打开的文件：**标准输入**（描述符为 0）、**标准输出**（描述符为 1）和**标准错误**（描述符为 2）。头文件 **\<unistd.h>** 定义了常量 STDIN\_FILENO、STDOUT\_FILENO 和 STDERR\_FILENO，它们可用来代替显式的描述符值。
* **改变当前的文件位置。**&#x5BF9;于每个打开的文件，内核保持着一个文件位置 k，初始为 0。这个文件位置是从文件开头起始的字节偏移量。应用程序能够通过执行 seek 操作，显式地设置文件的当前位置为 k。
* **读写文件。**&#x4E00;个读操作就是从文件复制 n > 0 个字节到内存，从当前文件位置 k 开始，然后将 k 增加到 k+n。给定一个大小为 m 字节的文件，当$$\small k\geqslant m$$时执行读操作会触发一个称为 end-of-file（EOF）的条件，应用程序能检测到这个条件。在文件结尾处并没有明确的 “EOF 符号”。

  类似地，写操作就是从内存复制 n > 0 个字节到一个文件，从当前文件位置 k 开始，然后更新 k。
* **关闭文件。**&#x5F53;应用完成了对文件的访问之后，它就通知内核关闭这个文件。作为响应，内核释放文件打开时创建的数据结构，并将这个描述符恢复到可用的描述符池中。无论一个进程因为何种原因终止时，内核都会关闭所有打开的文件并释放它们的内存资源。


---

# 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.1-unix-io.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.
