在 Linux 系统编程中,close() 是一个至关重要的系统调用,用于关闭一个打开的文件描述符(file descriptor)。
以下是关于 close() 函数的详细解析,包括原型、行为、返回值、常见陷阱以及最佳实践。
函数原型
#include <unistd.h> int close(int fd);
- 参数:
fd是要关闭的文件描述符。 - 返回值:
- 成功时返回
0。 - 失败时返回
-1,并设置errno以指示错误原因。
- 成功时返回
核心行为
当调用 close(fd) 时,内核执行以下操作:
-
引用计数检查:
- 每个打开的文件描述符在内核中都有一个引用计数。
- 如果该描述符是通过
dup()或fork()共享的,关闭它只会减少引用计数,不会立即释放底层资源。 - 只有当引用计数降为 0 时,内核才会真正释放该文件描述符占用的资源(如文件偏移量、打开文件状态标志等)。
-
释放资源:
- 如果引用计数为 0,内核会:
- 释放文件描述符槽位(使其可被新打开的文件复用)。
- 如果这是最后一个指向该打开文件表项的描述符,内核会执行
关闭操作
(如刷新缓冲区、通知文件系统更新 inode 等)。
- 如果引用计数为 0,内核会:
标准文件描述符:
close(0)关闭标准输入(stdin)。close(1)关闭标准输出(stdout)。close(2)关闭标准错误(stderr)。- 关闭这些描述符后,后续的 I/O 操作可能会失败或行为未定义,除非重新打开它们。
常见错误与 errno
| 错误码 | 含义 | 常见原因 |
|---|---|---|
EBADF |
文件描述符无效 | fd 不是有效的打开文件描述符(可能已关闭、从未打开或值非法) |
EINTR |
系统调用被信号中断 | 关闭操作被信号中断(罕见,但需处理) |
EIO |
I/O 错误 | 底层文件系统或设备发生错误 |
最佳实践与注意事项
✅ 始终检查返回值
if (close(fd) == -1) {
perror("close failed");
// 根据程序逻辑决定是否退出或继续
}
✅ 关闭后不再使用
- 关闭文件描述符后,不要再对该
fd进行任何操作(如,read
write,lseek),否则会导致EBADF错误。 - 建议将
fd设为-1作为标记:close(fd);fd = -1; // 防止误用
✅ 处理 EINTR
虽然 close() 很少被信号中断,但在编写健壮代码时,应处理 EINTR:
while (close(fd) == -1 && errno == EINTR) {
// 被信号中断,重试
}
if (errno != 0) {
perror("close failed");
}
✅ 与 dup() 和 fork() 的关系
fd是通过dup(fd)创建的,关闭其中一个副本不会影响另一个副本对底层文件的访问。- 在
fork()之后,子进程继承父进程的文件描述符,关闭父进程中的fd不会影响子进程中的副本,反之亦然。
✅ 资源泄漏
- 忘记关闭文件描述符会导致资源泄漏(文件描述符耗尽、内存泄漏等)。
- 在长时间运行的服务中,这可能导致程序崩溃或拒绝服务。
示例代码
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
int main() {
int fd = open("test.txt", O_RDONLY);
if (fd == -1) {

perror("open failed");
return 1;
}
// 使用 fd 进行 read/write 操作...
// 关闭文件描述符
if (close(fd) == -1) {
perror("close failed");
return 1;
}
// 防止误用
fd = -1;
printf("File closed successfully.n");
return 0;
}
常见问题 FAQ
Q: close() 会删除文件吗?
A: 不会。close() 只是关闭文件描述符,释放内核资源,要删除文件,应使用 unlink() 系统调用。
Q: 关闭标准输出(close(1))后,printf 还能用吗?
A: 不能。printf 默认写入标准输出(fd 1),关闭后,printf 会失败或行为未定义,如果需要重定向输出,应先使用 dup2() 将新文件描述符复制到 fd 1。
Q: 如何确保文件数据已写入磁盘?
A: close() 会触发内核将缓冲区中的数据刷新到磁盘(通过 fsync() 机制),但不能保证物理磁盘已写入,如需强一致性,应在 close() 前调用 fsync(fd)。
close() 是 Linux 文件 I/O 的基础操作,正确管理文件描述符的生命周期(打开 → 使用 → 关闭)是编写稳定、安全 C 程序的关键,务必检查返回值、处理错误,并避免资源泄漏。
首发原创文章,作者:世雄 - 原生数据库架构专家,如若转载,请注明出处:https://idctop.com/article/477760.html



