<fcntl.h> 文件控制
一、是什么
<fcntl.h> = file control,提供 C 风格的文件系统调用:
| 内容 | 用途 |
|---|---|
open() |
打开 / 创建文件 |
O_* 标志 |
控制打开方式 |
fcntl() |
修改 fd 属性 |
二、open 原型
cpp
int open(const char *pathname, int flags, mode_t mode);
| 参数 | 含义 |
|---|---|
pathname |
文件路径 |
flags |
打开方式(O_RDONLY、O_CREAT 等) |
mode |
权限,只在 O_CREAT 时用,如 0644 |
| 返回 | 成功 fd >= 0,失败 -1 |
三、常用标志
| 标志 | 含义 |
|---|---|
O_RDONLY |
只读 |
O_WRONLY |
只写 |
O_RDWR |
读写 |
O_CREAT |
不存在就创建 |
O_APPEND |
追加写,每次写到末尾 |
O_TRUNC |
打开时清空 |
O_EXCL |
配合 O_CREAT,文件已存在则失败 |
O_NONBLOCK |
非阻塞 |
多个标志用 | 组合:
cpp
open("data.log", O_CREAT | O_WRONLY | O_APPEND, 0644);
四、权限 0644
三位八进制:
6 4 4
│ │ └─ 其他人:r--
│ └─── 组:r--
└───── 拥有者:rw-
| 数字 | 权限 |
|---|---|
| 4 | 读 |
| 2 | 写 |
| 1 | 执行 |
| 6 | 读+写 |
| 7 | 读+写+执行 |
五、读 / 写 / 关闭
需要 #include <unistd.h>
unistd=Unix Standard
cpp
ssize_t read(int fd, void *buf, size_t count);
ssize_t write(int fd, const void *buf, size_t count);
int close(int fd);
| 返回值 | 含义 |
|---|---|
read > 0 |
实际读到的字节数 |
read = 0 |
文件读完 / 对端关闭 |
read = -1 |
出错 |
write > 0 |
实际写入的字节数 |
write = -1 |
出错 |
注意:write 可能写不全,大消息要循环写:
cpp
size_t total = 0;
while (total < len) {
ssize_t n = write(fd, buf + total, len - total);
if (n <= 0) break;
total += n;
}
六、落盘 fsync
需要 #include <unistd.h>
cpp
fsync(fd);
- 强制把内核缓冲区写到磁盘
- 防崩溃丢数据
- 比普通
write慢很多
WAL (预写日志)必须用:
cpp
write(fd, log.c_str(), log.size());
fsync(fd); // 确保真落盘
七、定位 lseek
cpp
off_t lseek(int fd, off_t offset, int whence);
whence |
含义 |
|---|---|
SEEK_SET |
从开头 |
SEEK_CUR |
从当前位置 |
SEEK_END |
从末尾 |
cpp
lseek(fd, 0, SEEK_SET); // 回到开头
八、最常用模板
追加写 + 落盘
cpp
int fd = open("data.log", O_CREAT | O_WRONLY | O_APPEND, 0644);
if (fd < 0) { /* 出错 */ }
std::string log = "SET key value\n";
write(fd, log.c_str(), log.size());
fsync(fd);
close(fd);
只读打开
cpp
int fd = open("data.txt", O_RDONLY);
char buf[1024];
ssize_t n;
while ((n = read(fd, buf, sizeof(buf))) > 0) {
// 处理 buf 前 n 字节
}
close(fd);
九、常见坑
| 坑 | 说明 |
|---|---|
open 返回 -1 要检查 |
不检查后面全崩 |
write 可能写不全 |
大消息要循环 |
fsync 很慢 |
别每条都调,重要才调 |
O_APPEND 保证原子追加 |
多线程写同一 fd 安全 |
fd 用完要 close |
否则泄漏 |
read 返回 0 |
是正常结束,不是错误 |
十、和 <fstream> 对比
<fcntl.h>(C 风格) |
<fstream>(C++ 风格) |
|
|---|---|---|
| 类型 | int fd |
ifstream / ofstream |
| 打开 | open("a.txt", O_RDONLY) |
ifstream in("a.txt") |
| 读 | read(fd, buf, n) |
getline(in, line) / in >> x |
| 写 | write(fd, buf, n) |
out << "hi" |
| 关闭 | close(fd) |
自动 / in.close() |
| 落盘 | fsync(fd) |
❌ |
| 非阻塞 | fcntl |
❌ |
| 网络 fd | ✅ 同一套 | ❌ |
| 逐行读 | ❌ 自己处理 | ✅ getline |
| 格式化输出 | ❌ | ✅ << |
| 跨平台 | Linux / POSIX | ✅ 全平台 |
| 底层 | 系统调用 | 封装系统调用 |
十一、怎么选
| 场景 | 用哪个 |
|---|---|
| 读文本、逐行处理 | ifstream + getline |
| 写文本 | ofstream |
要 fsync 落盘 |
open + write + fsync |
| 网络 socket | read / write |
| 要非阻塞 | fcntl |
| 跨平台 | fstream |
十二、总结
<fcntl.h>是 C 风格底层文件 IO:open打开,read/write读写,fsync落盘,close关闭。要落盘、要网络 fd、要非阻塞 → 用它;日常读文本 → 用
<fstream>。