open()
是 POSIX(Unix/Linux)系统调用,用于打开文件。它返回一个文件描述符(File Descriptor,简称 FD),用于后续读写操作。
#include // open() 需要 #include // 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
主要分为访问模式和附加模式,可使用 |
(位或)组合。
标志 | 含义 |
---|---|
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
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
off_t lseek(int fd, off_t offset, int whence);
fd
:文件描述符,表示已打开的文件。
offset
:偏移量,表示从参考点移动的字节数。
whence
:参考点,可以是以下值之一:
SEEK_SET
:从文件开头计算偏移量。
SEEK_CUR
:从当前文件偏移量计算偏移量。
SEEK_END
:从文件末尾计算偏移量。
此时,write函数会从当前的文件偏移量开始,向文件中写入数据
read()
函数#include
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';
在 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
会复制文件描述符,并指定新的文件描述符编号。如果目标文件描述符已打开,则会先关闭它。
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
是 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