Linux文件IO
1.open函数
open() 是 POSIX(Unix/Linux)系统调用,用于打开文件。它返回一个文件描述符(File Descriptor,简称 FD),用于后续读写操作。
头文件
#include <fcntl.h> // open() 需要 #include <unistd.h> // close() 需要
int open(const char *pathname, int flags);
int open(const char *pathname, int flags, mode_t mode);
参数
pathname:要打开的文件路径。flags:文件打开模式(必填)。mode:创建新文件时的权限(仅在O_CREAT标志位时需要)。-
返回值:成功返回文件描述符(非负整数),失败返回
-1,并设置errno以指示错误原因
flags(文件打开模式)
flags 主要分为访问模式和附加模式,可使用 |(位或)组合。
(1)基本访问模式(必选一个)
| 标志 | 含义 |
|---|---|
O_RDONLY | 只读打开文件 |
O_WRONLY | 只写打开文件 |
O_RDWR | 读写打开文件 |
mode(文件权限,仅 O_CREAT 时需要)
mode 以 八进制数(0开头) 指定文件权限,如 0644。
| 权限 | 八进制表示 | 说明 |
|---|---|---|
rw-r--r-- | 0644 | 所有者可读写,组和其他用户仅可读 |
rwxr-xr-x | 0755 | 所有者可读写执行,组和其他用户可读执行 |
rwx------ | 0700 | 仅所有者可读写执行 |
2.write() 函数
#include <unistd.h>
ssize_t write(int fd, const void *buf, size_t count);
参数
-
fd:文件描述符,表示已打开的文件。 -
buf:指向要写入数据的缓冲区的指针。 -
count:要写入的字节数。
返回值
-
成功时:返回实际写入的字节数(通常等于
count)。 -
失败时:返回
-1,并设置errno。
lseek() 函数
作用
-
移动文件的读写指针(文件偏移量)。
-
可以指定参考点(
SEEK_SET、SEEK_CUR、SEEK_END)和偏移量。
#include <unistd.h>
off_t lseek(int fd, off_t offset, int whence);
-
fd:文件描述符,表示已打开的文件。 -
offset:偏移量,表示从参考点移动的字节数。 -
whence:参考点,可以是以下值之一:-
SEEK_SET:从文件开头计算偏移量。 -
SEEK_CUR:从当前文件偏移量计算偏移量。 -
SEEK_END:从文件末尾计算偏移量。
-
此时,write函数会从当前的文件偏移量开始,向文件中写入数据
3. read() 函数
#include <unistd.h>
ssize_t read(int fd, void *buf, size_t count);
参数
-
fd:文件描述符,表示已打开的文件。 -
buf:指向存储读取数据的缓冲区的指针。 -
count:要读取的字节数。
返回值
-
成功时:返回实际读取的字节数(可能小于
count,如果文件末尾已到达)。 -
失败时:返回
-1,并设置errno。
注意最后最好在buf尾加上"\0"
ssize_t bytes_read = read(fd, buf, sizeof(buf) - 1); // 留一个字节给 '\0'
// 添加字符串终止符
buf[bytes_read] = '\0';
4.dup函数
在 Linux 中,dup、dup2 和 dup3 函数用于复制文件描述符,以下是它们的作用和区别:
dup
-
作用:复制一个文件描述符,返回一个新的描述符,指向同一个文件或资源。
-
特点:新描述符是当前可用描述符中编号最小的。
-
函数原型:
int dup(int oldfd); -
参数:
-
oldfd:要复制的文件描述符。
-
-
返回值:成功时返回新的文件描述符,失败时返回 -1 并设置
errno。
// 复制文件描述符
int new_fd = dup(fd);
if (new_fd == -1) {
perror("dup");
return 1;
}
printf("Original fd: %d, Duplicated fd: %d\n", fd, new_fd);
运行结果
-
打开文件
test.txt,原始文件描述符为fd。 -
使用
dup复制fd,得到新的文件描述符new_fd。 -
向
fd和new_fd写入数据,数据都会写入同一个文件test.txt。
dup2
dup2 会复制文件描述符,并指定新的文件描述符编号。如果目标文件描述符已打开,则会先关闭它。
int fd = open("test.txt", O_WRONLY | O_CREAT, 0644);
if (fd == -1) {
perror("open");
return 1;
}
// 将标准输出(文件描述符 1)重定向到文件
if (dup2(fd, STDOUT_FILENO) == -1) {
perror("dup2");
return 1;
}
// 现在 printf 会写入文件,而不是终端
printf("This is written to the file via dup2!\n");
运行结果
-
打开文件
test.txt,文件描述符为fd。 -
使用
dup2将标准输出(文件描述符 1)重定向到fd。 -
调用
printf时,输出会写入文件test.txt,而不是终端。
dup3
dup3 是 dup2 的扩展版本,支持设置额外的标志(如 O_CLOEXEC)。
int fd = open("test.txt", O_WRONLY | O_CREAT, 0644);
if (fd == -1) {
perror("open");
return 1;
}
// 使用 dup3 复制文件描述符,并设置 O_CLOEXEC 标志
int new_fd = dup3(fd, 10, O_CLOEXEC);
if (new_fd == -1) {
perror("dup3");
return 1;
}
printf("Original fd: %d, Duplicated fd: %d\n", fd, new_fd);
// 写入数据
write(fd, "Hello from fd\n", 14);
write(new_fd, "Hello from new_fd\n", 18);
-
打开文件
test.txt,文件描述符为fd。 -
使用
dup3复制fd,并指定新的文件描述符为10,同时设置O_CLOEXEC标志。 -
向
fd和new_fd写入数据,数据都会写入同一个文件test.txt。
总结:
如果你只是想复制一个文件描述符,使用 dup
如果你需要重定向文件描述符(如将标准输出重定向到文件),使用 dup2
如果你需要在dup2基础上实现更精细的控制(如设置 O_CLOEXEC 标志),使用 dup3
