文件 I/O 基础 — open/read/write/close 与一次完整的性能实验¶
这一章讲什么: 系统程序最基础的动作——读写文件——在 Unix 里只用 四个系统调用:
open()、read()、write()、close()。它们对磁盘文件、 终端、打印机一视同仁,这就是 Unix 的「万能 I/O」。本章把四个调用 每个讲透,配上仿写cp的完整项目;然后用一组实测回答一个真问题: 拷贝程序的缓冲区到底开多大? 答案藏在系统调用开销和内核缓冲的 博弈里。
1. 顶层全景:三个对象,四个调用¶
Unix I/O 的全部机制可以压成一张图:
进程的文件描述符表 全系统的打开文件表 每个文件系统的
(每个进程一张) (file structure table) 活动 inode 表
┌───┬─────┐ ┌───┬────────────┐
│ 0 │ ────┼──────────────►│FS0│ 文件偏移 │──► inode ──► 磁盘上的文件
│ 1 │ ────┼──► (stdout) │FS1│ 标志/模式 │
│ 2 │ ────┼──► (stderr) │FS2│ inode 指针 │
│ 3 │ ────┼──────────────►│FS3│ 引用计数 │
└───┴─────┘ └───┴────────────┘
打开:在表里新建一个 FS 项,返回下标 = 文件描述符
读/写:按 fd 找到 FS 项 → 按 inode 指针找数据 → 移动偏移
关闭:删掉描述符项;FS 项引用计数归零才真正释放
图说:文件描述符只是进程私有表里的下标;真正的连接状态(偏移、标志) 在内核的全局打开文件表里;inode 才把连接落到磁盘上的文件1。 这套结构解释了本章大部分「为什么」:为什么同一文件能被多个进程同时开 (各自一条 FS 项)、为什么两次 open 互不影响偏移、为什么 close 删的只是 连接、以及第 13 章 dup 是怎么让两个描述符共享一个偏移的。
三个术语钉死:连接 = 打开文件描述(open file description, OFD); 引用 = 文件描述符(file descriptor, 一个小的非负整数); 访问模式 = 只读 / 只写 / 读写(存在 OFD 里)2。
主线例子:spl_cp1——仿写 cp 命令。一个具体输入:把一个 57,569,256 字节 的文件拷到新文件,缓冲区 4096 字节。每一步的状态变化都会标出来。
2. 先补两门前置课:umask 与进程的身份证¶
umask:创建文件时的权限过滤器¶
第 1 章说过权限,这里是它在创建时刻的机制。每个进程有一个文件创建
掩码,9 位,通称 umask:某位为 1,表示「创建时把对应的权限位关掉」。
应用方式是按位与: 实际权限 = mode & ~umask3。走一遍原书的例子:
进程想要 mode = 110 110 010 (rwxrw-r-x 的位表示)
umask = 000 010 010 (八进制 022)
~umask = 111 101 101
────────────────────────────
mode & ~umask = 110 100 000 → rw-r----- …即用户读写、组只读、其他人没有
图说:022 是常见默认值——「别人可读但不可写」4。想更狠一点用 066:
其他人的读写全关。不想记补码,可以记「减法」形式:umask 里有的位就从 mode
里抠掉(0-1=0)5。登录时 shell 拿到默认 umask(常是 022),进程从
shell 继承、再传给它的子进程;umask 命令查看(-S 看符号形式),
umask 033 修改,写进 .bashrc 永久生效6。
进程的四个用户 ID 与 setuid¶
权限检查要回答「你是谁」——但「你」不止一个 ID。Linux 上每个进程有 四个用户 ID:真实用户 ID(real)、有效用户 ID(effective)、 保存的 set-user-ID(saved)、文件系统用户 ID(filesystem,Linux 特有)。 平时四者相等;内核做权限判断用的是有效用户 ID(Linux 理论上用 filesystem UID,但它恒等于 effective UID,结果一样)7。
什么时候不等?文件模式里有个 setuid 位(12 个模式位中的最高位)。
一个可执行文件设了 setuid 位,别人运行它时,进程的有效 UID 变成文件
所有者的 UID,真实 UID 仍是运行者8。教科书案例是 passwd:
$ ls -l /usr/bin/passwd
-rwsr-xr-x 1 root root 59976 Nov 24 07:05 passwd ← 用户位是 s
$ ps -o euid,ruid,pid,args -C passwd
EUID RUID PID COMMAND
0 500 14561 passwd ← 有效 0( root ),真实 500(你)
图说:普通用户凭什么改 /etc/shadow?凭的是「此刻我体内住着 root 的 有效身份」;而 saved set-user-ID 存着这个有效身份,供程序临时降权再 升回来时用9。「程序修改自己有效 UID」这类程序就叫 setuid 程序—— 安全史上漏洞最多的程序类别,第 11 章会再遇见。
判断(我们的,不是书里的): 「有效 UID 才是办事的身份证」这条, 是整个 Unix 权限模型里最常被半懂的人误解的一点——很多人以为文件 「属于谁」由真实 UID 决定。记住口令:open() 创建文件时,文件所有者 记的是有效 UID(man 页原文),不是真实 UID。setuid 程序创建的文件的 归属,就是这个规则的直接推论。 如果错,会错在: Linux 特有的 filesystem UID 在极少数场景 (NFS、显式 setfsuid)下与 effective UID 短暂分离;那时「按 effective 判断」这句话在文件访问上就不精确——但日常系统编程几乎碰不到。
3. open():连接的诞生¶
找函数:apropos 的筛选¶
老流程:apropos -s2 open 列出候选——creat、open、openat、
openat2。后两个是 open 的扩展版(openat 相对目录打开;openat2 更灵活
但没有 glibc 包装、Linux 独有,本书不用);creat() 本质是 open 的
特例。结论:研究 open()10。一个细节:这几个系统调用声明在
<fcntl.h> 而不是 <unistd.h>(第 2 章说过系统调用声明「几乎」都在
unistd.h——这是例外之一)11。
flags:一扇大门上的三组开关¶
第二个参数是位掩码,必须含三个访问模式之一:O_RDONLY /
O_WRONLY / O_RDWR;再按需或上创建标志12。创建相关的三个13:
| 标志 | 作用 | 组合后的行为 |
|---|---|---|
O_CREAT |
不存在就创建 | 只加它:已存在则从开头覆盖、尾部保留(想不到吧) |
O_TRUNC |
存在则截断成 0 长 | O_WRONLY\|O_CREAT\|O_TRUNC = 覆盖或新建(最常见的「写文件」组合) |
O_EXCL |
与 O_CREAT 同用 | O_WRONLY\|O_CREAT\|O_EXCL = 新建,已存在则报错(锁文件/临时文件的套路) |
图说:三种组合对应三种意图——覆盖写、原子新建、追加(追加没有标志,
要到第 11 章用 O_APPEND)。 还有反面教材:O_RDWR|O_CREAT|O_TRUNC
会把文件清空再读写——「打开来读,结果内容没了」,务必确认真想要14。
第三个参数 mode 只在创建时生效,用 <sys/stat.h> 的符号常量按位或
(S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH = rw-r--r--)15。两条纪律:
传了 O_CREAT 就必须传 mode(不传则权限不可预测);最终权限还要过
umask 这一关16。失败返回 -1,errno 说原因(不存在、没权限、目录没写
权限、O_EXCL 撞车……),处理模板就是 fatal_error(errno, ...)17。
4. close():断开连接,以及为什么 write 成功不等于落盘¶
close(fd) 关的是描述符;只有它是最后一个指向该 OFD 的引用时,
OFD 才释放18。man 页里还有一句重物:若 fd 是对一个已被 unlink 的
文件的最后一个引用,文件就被删除——第 7 章讲链接时会兑现。
close 也会失败,原因值得枚举19:
EBADF:fd 本身非法;EINTR:内核在 close 执行中被急事打断;POSIX 不规定此时 fd 到底 关没关——有的实现关了,有的没关要重试,而重试在多线程程序里有风险; man 页建议:失败后不要重试 close();EIO/ENOSPC/EDQUOT:磁盘满了、配额超了——对写打开的文件, 有些错误要到 close 才冒头(数据其实还在内核缓冲里没写下去)。
于是有了「认真版」收尾:fsync() 先把缓冲区的数据强刷到设备,
错误在 close 之前暴露;再 close。fsync 只对磁盘文件有效(否则 EINVAL,
忽略它)20。这正是主线例子里 spl_cp1 对目标文件做的:fsync(target)
→ close(target)21。write 成功的瞬间,数据多半只是进了内核缓冲
(buffer cache),何时落盘由内核决定——这是全章最重要的「隐性契约」,
性能实验和 close 错误都源于此22。
5. read() 与 write():搬运字节,以及「短读不是错」¶
read():可能比你要的少¶
从 fd 当前偏移起,至多读 nbytes 字节到 buf,返回实际读到的字节数; 返回 0 = 读到文件尾;返回 -1 = 错,errno 有细节23。三条要点:
- 返回值可能小于请求值,而且这不叫错误。 文件只剩 256 字节时,三次 read(100) 依次返回 100、100、56(再读返 0)。如果以为「要 100 就得 100」, 拷贝程序会静默丢数据。
- 每次 read 从「上次结束的地方」接着读——OFD 里的文件偏移自动前进, 这是顺序遍历文件的全部机制。
- buf 只是临时货仓:下次调用会覆盖它,数据要用就得赶紧搬走。
标准读循环(主线例子的核心):
while ( (num_bytes_read = read(source_fd, buffer, BUFFER_SIZE)) > 0 ) {
/* buffer[0 .. num_bytes_read-1] 是本次数据,立刻处理(比如 write 出去) */
}
if ( num_bytes_read == -1 )
fatal_error(errno, "error reading");
write():对称,也有「短写」¶
成功返回实际写出的字节数;不为 -1 不代表写全了——短写可能由文件到顶、
磁盘满、配额尽引起。认真的写法是三个分支都处理: -1 报错、
返回值 < nbytes 报「部分写」、全等才算过24。
标准文件描述符:0、1、2¶
进程从 shell 出生就带三个打开的连接:0 = 标准输入(stdin,键盘)、
1 = 标准输出(stdout,屏幕)、2 = 标准错误(stderr,屏幕);
程序里用符号常量 STDIN_FILENO / STDOUT_FILENO / STDERR_FILENO
(定义在 unistd.h)而不是裸数字25。进程终止时它们自动关闭——这就是
你从没显式关过 stdout 的原因26。它们只是「预先打开的三个 fd」,
完全可以当文件用:write(1, ...) 就是打印,read(0, ...) 就是读键盘,
重定向(第 18 章)就是把它们改指别处。
6. 主线例子走查:spl_cp1 拷一个 57,569,256 字节的文件¶
完整程序的逻辑骨架(错误处理从简,只留结构):
#define BUFFER_SIZE 4096
#define PERMISSIONS S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH /* rw-rw-r-- */
if ( argc != 3 ) usage_error("spl_cp1 source destination");
source_fd = open(argv[1], O_RDONLY); /* ① 开源:只读 */
target_fd = open(argv[2], O_WRONLY | O_CREAT | O_TRUNC, PERMISSIONS);
/* ② 开目标:覆盖或新建 */
while ( (num_bytes_read = read(source_fd, buffer, BUFFER_SIZE)) > 0 ) {
num_bytes_written = write(target_fd, buffer, num_bytes_read);
if ( errno != 0 ) fatal_error(errno, "copy"); /* ③ 循环:4096 字节一推 */
if ( num_bytes_written != num_bytes_read )
fatal_error(-1, "write error to target"); /* 部分写也要抓 */
}
if ( num_bytes_read == -1 ) fatal_error(errno, "error reading");
close(source_fd);
fsync(target_fd); /* ④ 认真收尾 */
close(target_fd);
图说:57,569,256 ÷ 4096 = 14,055 次循环,每次「满读→整写」,
最后余 2,952 字节一次短读短写。 缓冲区大小用 #ifndef BUFFER_SIZE
包着,编译时用 -DBUFFER_SIZE=8192 可以在不改源码的情况下做实验27。
测试:正确性怎么证明¶
- 空文件:
du -b显示 0 字节,拷完还是 0——走一遍,边界不炸。 - 中等文件(约 55MB):拷完用
cmp比——cmp 比 diff 强,二进制文件 也比得出,无输出即全同28。 - 超大文件 + 写错误:把 13,129,809,920 字节的虚拟机镜像往只有
约 8GB 的盘上拷,程序报
write error to /temp/largefile—— errno==0 但返回值不足的「部分写」分支被命中;再补一次 write 就会拿到 ENOSPC("No space left on device")29。
万能 I/O 的实证:同一个程序拷终端¶
同一个 spl_cp1 二进制,零修改:
$ ./spl_cp1 testfile /dev/tty → 文件内容出现在终端上(/dev/tty 就是终端设备文件)
$ ./spl_cp1 /dev/tty newfile → 你敲的键盘内容存进 newfile(CTRL-D 结束)
$ ./spl_cp1 /dev/tty /dev/pts/2 → 窗口 1 输入,出现在窗口 2
图说:「系统调用对所有文件一视同仁」不是口号,是 spl_cp1 三个不同 运行方式证明的事实30。read 从终端返回 0 的唯一条件是 CTRL-D—— 终端没有「文件尾」,只有「这次输入到此为止」。
7. 性能实验一:三种时间和系统调用的真实开销¶
time 命令:real / user / sys¶
/usr/bin/time -p 命令(注意全路径——bash 有自己的 time 内建,行为
不同)输出三个数31:
| 值 | 含义 |
|---|---|
| real | 墙上时钟:从启动到结束的总秒数 |
| user | 用户态 CPU 时间:你的代码跑的时长 |
| sys | 内核态 CPU 时间:替你干活时内核跑的时长 |
real ≥ user + sys,差值是「不在 CPU 上的时间」:等 I/O(进程被 阻塞,block——没拿到必需资源就不许上 CPU)和在就绪队列里排队等 CPU。 实测拷 116MB:spl_cp1 用 real 0.73s(user 0.02 + sys 0.14), 0.57 秒不在 CPU 上——I/O 等待占大头32。
系统调用开销:28 倍的价格¶
两个微基准,各跑 1 亿次调用(Linux 5.15 内核):调 uname()(小而快的
系统调用)用 42.25 秒;调 rand()(等价的库函数,内部只是查表算数)
用 1.47 秒——差约 28 倍,就是 trap、搬参数、查向量表这些「进出内核」
步骤的价格33。推论:系统调用次数是 I/O 程序的关键性能变量。
8. 性能实验二:缓冲区多大合适(本章的高潮)¶
实验设计要控制一个大干扰:内核缓冲(buffer cache)。read 不是直接从
磁盘搬进你的内存,而是「磁盘 → 内核的 buffer cache → 你的地址空间」;
write 同理先落 cache。好处:重复读同一文件第二次全走内存;坏处:你不
清空 cache,多次测量的就不是同一件事。所以测试脚本每次跑之前
umount /temp 再 mount /temp,强行清空缓冲34。
17 档缓冲区、每档跑 5 次取平均,结果(拷贝同一文件的总时间):
| 缓冲区 | real(s) | sys(s) | 缓冲区 | real(s) | sys(s) |
|---|---|---|---|---|---|
| 1 B | 214.2 | 155.6 | 1,024 | 0.82 | 0.25 |
| 16 B | 14.0 | 9.8 | 4,096 | 0.64 | 0.13 |
| 128 B | 2.27 | 1.34 | 8,192 | 0.64 | 0.11 |
| 512 B | 1.01 | 0.40 | 65,536 | 0.61 | 0.11 |
| 256 B | 1.47 | 0.72 | — | — | — |
图说:小缓冲区段,翻倍缓冲区≈减半系统时间(系统调用数减半); 4KB 之后曲线变平,因为总搬运时间成了地板35。机理分两层:
- 系统调用有固定开销(实验一),调用次数 = 文件大小 ÷ 缓冲区,所以小 缓冲区时 sys 时间随缓冲区翻倍而对半砍;
- 但总字节数不变,总搬运时间不变——把开销摊薄到零,也快不过搬运 本身。这就是收益递减;缓冲区超过文件大小纯属浪费(内核还得白配内存)36。
对照行业水平:GNU coreutils 的 cp(9.6 版)用 128KB(运行时由
io_blksize() 按块设备选),比我们随手写的 4096 大 32 倍37。
我们自己的程序可以自信地选 4KB–8KB,除非有证据需要更大。
9. 作者的判断与证据¶
有实验数据撑着的(本章的强项):
- 系统调用比库函数贵约 28 倍(1 亿次对照)33;
- 缓冲区-时间曲线全表,含清空 cache 的对照手法3435;
- time() vs clock_gettime() 式的选型思路延续——实测而非迷信文档。
作者的判断:
- 「spl_cp1 的正确性靠空/中/超大文件 + cmp 抽样「高度确信」」—— 这是工程上的实用主义:穷举不可能,分层测试可以把风险压到可接受28。
- 「write 部分写后可以直接报错退出,也可以重写剩余」——两种处置都给了, 选哪种留给场景24。
10. 边界与局限¶
- O_APPEND、文件锁、非阻塞 I/O 这些 flags 本章故意没讲(散在第 11、 12、17 章)。
- 缓冲区实验的文件系统结论只对被测系统负责;别的文件系统、别的内核 版本的拐点可能不同——方法(清 cache、多次取平均)比数字值钱36。
- close 的 EINTR 可移植处理被如实标为「难」,给了 Linux 上的简化版, 跨平台要自己再查19。
- spl_cp1 不保留时间戳等属性(那是
cp -p的领域,第 6 章的 stat 才能做)。
11. 可带走的¶
主线例子,一行复述: 开源头(O_RDONLY)→ 开目标(O_WRONLY|O_CREAT| O_TRUNC, mode=rw-rw-r-- 过 umask)→ while((n=read(src,buf,4096))>0) write(dst,buf,n) 并查部分写 → fsync + close 目标。
- Unix I/O = open/read/write/close 四调用,对一切非目录文件(含设备)通用。
- fd 是进程描述符表的下标;OFD 在内核全局表里,存偏移;inode 指向磁盘文件。
- read/write 都可能「短」——返回 ≠ 请求不是错误,是必须处理的常态。
- O_CREAT 必须配 mode;组合意图记三种:覆盖写(TRUNC)、原子新建(EXCL)、 追加(没有标志,第 11 章 O_APPEND)。
- umask = 创建时的权限过滤器(mode & ~umask);022 常见,066 更严。
- 权限按「有效 UID」判;setuid 位让进程的有效身份换主人(passwd 模式)。
- write 成功 ≠ 落盘;认真收尾 = fsync() 再 close(),close 失败别重试。
- 0/1/2 是 stdin/stdout/stderr,进程出生自带、自动关闭,可当普通文件用。
- 系统调用比库函数贵约 28 倍;I/O 循环的缓冲区 ≥ 4KB,coreutils 用 128KB。
- 测 I/O 性能前 umount/mount 清 buffer cache,否则测的是内存速度。
- time -p 的 real − (user+sys) = 阻塞等待 + 排队时间。
12. 原文地图¶
| 主题 | 原书章 | 原文位置 |
|---|---|---|
| umask 位运算与传播 | Chapter 4: Basic Concepts of File I/O | text/10-ch04-chapter-4-basic-concepts-of-file-i-o.txt:93(搜「bitwise」) · :104(搜「common value」) · :166(搜「from the shell」) |
| 四个用户 ID、setuid、passwd | 同上 | :182(搜「four user IDs」) · :204(搜「setuid bit」) · :223(搜「-rwsr-xr-x」) · :236(搜「EUID RUID」) |
| OFD、fd、I/O 三步 | 同上 | :257(搜「open file description」) · :339(搜「three steps」) |
| 三张内核表结构 | 同上 | :288(搜「User space」) · :318(搜「file structure table」) |
| 标准描述符 0/1/2 | 同上 | :345(搜「inherits three」) · :354(搜「STDIN_FILENO」) |
| open 研究与 flags | 同上 | :387(搜「apropos -s2 open」) · :422(搜「these are system calls」) · :442(搜「bit mask」) · :490(搜「O_CREAT」) · :512(搜「O_TRUNC」) · :520(搜「O_EXCL」) |
| mode 常量与创建规则 | 同上 | :563(搜「unpredictable」) · :571(搜「S_IRWXU」) |
| close 错误与 fsync | 同上 | :630(搜「close a file descriptor」) · :689(搜「should not retry」) · :694(搜「fsync」) |
| read 语义与读循环 | 同上 | :779(搜「ssize_t read」) · :802(搜「Figure 4-2」) · :845(搜「done = FALSE」) · :893(搜「can't assume」) |
| write 与短写 | 同上 | :930(搜「ssize_t write」) · :965(搜「predefined maximum」) · :989(搜「kernel buffers」) |
| spl_cp1 完整程序 | 同上 | :1127(搜「BUFFER_SIZE 4096」) · :1182(搜「Flush data to device」) |
| 测试策略与 ENOSPC | 同上 | :1248(搜「cmp」) · :1283(搜「13,129,809,920」) |
| 万能 I/O 演示 | 同上 | :1309(搜「/dev/tty」) · :1345(搜「/dev/pts/2」) |
| time 命令三时间 | 同上 | :1375(搜「time -p」) · :1417(搜「blocked」) |
| 系统调用开销实验 | 同上 | :1480(搜「42.25」) · :1485(搜「1.47」) |
| buffer cache 与清缓存 | 同上 | :1508(搜「storage area」) · :1553(搜「unmount」) |
| 缓冲区实验数据 | 同上 | :1582(搜「214.242」) · :1594(搜「4,096」) · :1611(搜「diminishing returns」) |
| coreutils 的 128KB | 同上 | :1625(搜「io_blksize」) |
-
出处:「Chapter 4: Basic Concepts of File I/O」第 248–343 段(
text/10-ch04-chapter-4-basic-concepts-of-file-i-o.txt:288,搜「User space」) · :318(搜「file structure table」)。图是原书 Figure 4-1 的重绘。 ↩ -
出处:「Chapter 4: Basic Concepts of File I/O」第 248–269 段(
text/10-ch04-chapter-4-basic-concepts-of-file-i-o.txt:257,搜「open file description」)。 ↩ -
出处:「Chapter 4: Basic Concepts of File I/O」第 92–94 段(
text/10-ch04-chapter-4-basic-concepts-of-file-i-o.txt:93,搜「bitwise」)。 ↩ -
出处:「Chapter 4: Basic Concepts of File I/O」第 95–105 段(
text/10-ch04-chapter-4-basic-concepts-of-file-i-o.txt:104,搜「common value」)。 ↩ -
出处:「Chapter 4: Basic Concepts of File I/O」第 115–124 段(
text/10-ch04-chapter-4-basic-concepts-of-file-i-o.txt:124,搜「filter」)。 ↩ -
出处:「Chapter 4: Basic Concepts of File I/O」第 126–172 段(
text/10-ch04-chapter-4-basic-concepts-of-file-i-o.txt:143,搜「u=rwx」) · :166(搜「from the shell」)。 ↩ -
出处:「Chapter 4: Basic Concepts of File I/O」第 174–200 段(
text/10-ch04-chapter-4-basic-concepts-of-file-i-o.txt:182,搜「four user IDs」)。 ↩ -
出处:「Chapter 4: Basic Concepts of File I/O」第 202–218 段(
text/10-ch04-chapter-4-basic-concepts-of-file-i-o.txt:202,搜「setuid bit」)。 ↩ -
出处:「Chapter 4: Basic Concepts of File I/O」第 219–246 段(
text/10-ch04-chapter-4-basic-concepts-of-file-i-o.txt:223,搜「-rwsr-xr-x」) · :236(搜「EUID RUID」)。 ↩ -
出处:「Chapter 4: Basic Concepts of File I/O」第 383–431 段(
text/10-ch04-chapter-4-basic-concepts-of-file-i-o.txt:387,搜「apropos -s2 open」)。 ↩ -
出处:「Chapter 4: Basic Concepts of File I/O」第 412–427 段(
text/10-ch04-chapter-4-basic-concepts-of-file-i-o.txt:424,搜「in fcntl.h」)。 ↩ -
出处:「Chapter 4: Basic Concepts of File I/O」第 433–458 段(
text/10-ch04-chapter-4-basic-concepts-of-file-i-o.txt:442,搜「bit mask」)。 ↩ -
出处:「Chapter 4: Basic Concepts of File I/O」第 483–526 段(
text/10-ch04-chapter-4-basic-concepts-of-file-i-o.txt:490,搜「O_CREAT」) · :512(搜「O_TRUNC」) · :520(搜「O_EXCL」)。 ↩ -
出处:「Chapter 4: Basic Concepts of File I/O」第 527–535 段(
text/10-ch04-chapter-4-basic-concepts-of-file-i-o.txt:1042,搜「truncates the file」)。 ↩ -
出处:「Chapter 4: Basic Concepts of File I/O」第 561–586 段(
text/10-ch04-chapter-4-basic-concepts-of-file-i-o.txt:571,搜「S_IRWXU」)。 ↩ -
出处:「Chapter 4: Basic Concepts of File I/O」第 561–564 段(
text/10-ch04-chapter-4-basic-concepts-of-file-i-o.txt:563,搜「unpredictable」)。 ↩ -
出处:「Chapter 4: Basic Concepts of File I/O」第 588–611 段(
text/10-ch04-chapter-4-basic-concepts-of-file-i-o.txt:601,搜「fatal_error」)。 ↩ -
出处:「Chapter 4: Basic Concepts of File I/O」第 625–665 段(
text/10-ch04-chapter-4-basic-concepts-of-file-i-o.txt:630,搜「close a file descriptor」)。 ↩ -
出处:「Chapter 4: Basic Concepts of File I/O」第 667–699 段(
text/10-ch04-chapter-4-basic-concepts-of-file-i-o.txt:672,搜「EBADF」) · :686(搜「ENOSPC」) · :689(搜「should not retry」)。 ↩↩ -
出处:「Chapter 4: Basic Concepts of File I/O」第 693–726 段(
text/10-ch04-chapter-4-basic-concepts-of-file-i-o.txt:694,搜「fsync」)。 ↩ -
出处:「Chapter 4: Basic Concepts of File I/O」第 1124–1192 段(
text/10-ch04-chapter-4-basic-concepts-of-file-i-o.txt:1182,搜「Flush data to device」)。 ↩ -
出处:「Chapter 4: Basic Concepts of File I/O」第 987–991 段(
text/10-ch04-chapter-4-basic-concepts-of-file-i-o.txt:989,搜「kernel buffers」)。 ↩ -
出处:「Chapter 4: Basic Concepts of File I/O」第 728–898 段(
text/10-ch04-chapter-4-basic-concepts-of-file-i-o.txt:779,搜「ssize_t read」) · :894(搜「not an error」)。 ↩ -
出处:「Chapter 4: Basic Concepts of File I/O」第 960–985 段(
text/10-ch04-chapter-4-basic-concepts-of-file-i-o.txt:1290,搜「fewer than」)。 ↩↩ -
出处:「Chapter 4: Basic Concepts of File I/O」第 344–356 段(
text/10-ch04-chapter-4-basic-concepts-of-file-i-o.txt:348,搜「standard input」) · :354(搜「STDIN_FILENO」)。 ↩ -
出处:「Chapter 4: Basic Concepts of File I/O」第 364–366 段(
text/10-ch04-chapter-4-basic-concepts-of-file-i-o.txt:364,搜「closed automati」)。 ↩ -
出处:「Chapter 4: Basic Concepts of File I/O」第 1117–1221 段(
text/10-ch04-chapter-4-basic-concepts-of-file-i-o.txt:1126,搜「#ifndef BUFFER_SIZE」) · :1198(搜「-DBUFFER_SIZE」)。 ↩ -
出处:「Chapter 4: Basic Concepts of File I/O」第 1224–1293 段(
text/10-ch04-chapter-4-basic-concepts-of-file-i-o.txt:1237,搜「identical copies」) · :1248(搜「cmp」)。 ↩↩ -
出处:「Chapter 4: Basic Concepts of File I/O」第 1280–1293 段(
text/10-ch04-chapter-4-basic-concepts-of-file-i-o.txt:1283,搜「13,129,809,920」)。 ↩ -
出处:「Chapter 4: Basic Concepts of File I/O」第 1295–1353 段(
text/10-ch04-chapter-4-basic-concepts-of-file-i-o.txt:1309,搜「/dev/tty」) · :1345(搜「/dev/pts/2」)。 ↩ -
出处:「Chapter 4: Basic Concepts of File I/O」第 1355–1399 段(
text/10-ch04-chapter-4-basic-concepts-of-file-i-o.txt:1375,搜「time -p」)。 ↩ -
出处:「Chapter 4: Basic Concepts of File I/O」第 1400–1427 段(
text/10-ch04-chapter-4-basic-concepts-of-file-i-o.txt:1404,搜「chimera」) · :1423(搜「0.57」)。 ↩ -
出处:「Chapter 4: Basic Concepts of File I/O」第 1465–1488 段(
text/10-ch04-chapter-4-basic-concepts-of-file-i-o.txt:1480,搜「42.25」) · :1485(搜「1.47」)。 ↩↩ -
出处:「Chapter 4: Basic Concepts of File I/O」第 1489–1556 段(
text/10-ch04-chapter-4-basic-concepts-of-file-i-o.txt:1515,搜「buffer cache」) · :1553(搜「unmount」)。 ↩↩ -
出处:「Chapter 4: Basic Concepts of File I/O」第 1557–1621 段(
text/10-ch04-chapter-4-basic-concepts-of-file-i-o.txt:1582,搜「214.242」) · :1600(搜「roughly」)。 ↩↩ -
出处:「Chapter 4: Basic Concepts of File I/O」第 1600–1621 段(
text/10-ch04-chapter-4-basic-concepts-of-file-i-o.txt:1611,搜「diminishing returns」) · :1619(搜「larger than the file」)。 ↩↩ -
出处:「Chapter 4: Basic Concepts of File I/O」第 1622–1627 段(
text/10-ch04-chapter-4-basic-concepts-of-file-i-o.txt:1625,搜「io_blksize」)。 ↩