在C语言中,open
、write
和read
函数是系统调用(system calls),它们直接由操作系统提供,用于底层的文件操作。这些函数是UNIX和类UNIX系统(如Linux)中的标准接口,不同于C标准库中的文件操作函数(如fopen
、fwrite
和fread
)。
open
open函数用于打开一个文件或创建一个新文件,并返回一个文件描述符。这个函数在C语言的标准库中定义在<fcntl.h>头文件中。
c
#include <fcntl.h>
int fd = open(const char *pathname, int flags, mode_t mode);
pathname
:要打开的文件的路径。flags
:文件打开的模式标志,例如O_RDONLY
(只读)、O_WRONLY
(只写)、O_RDWR
(读写)、O_CREAT
(如果文件不存在则创建)等。mode
:文件创建时的权限模式,通常是一个三位八进制数,例如0666
表示读写权限。
返回值:
- 成功时返回一个文件描述符(非负整数)。
- 失败时返回
-1
,并设置errno
。
常见的 flags
-
O_RDONLY
:- 只读模式打开文件。
- 文件描述符用于读取操作。
-
O_WRONLY
:- 只写模式打开文件。
- 文件描述符用于写入操作。
-
O_RDWR
:- 读写模式打开文件。
- 文件描述符可以用于读取和写入操作。
-
O_CREAT
:- 如果文件不存在,则创建文件。
- 需要提供
mode
参数来设置文件权限(如果文件被创建)。
-
O_TRUNC
:- 如果文件已存在且以写入模式打开,则截断文件为零长度(即清空文件内容)。
-
O_APPEND
:- 以追加模式打开文件。
- 写入数据时,数据将被追加到文件的末尾,而不是覆盖文件的现有内容。
-
O_EXCL
:- 与
O_CREAT
一起使用时,如果文件已经存在,则open
调用失败。 - 用于确保文件的创建是唯一的。
- 与
-
O_NONBLOCK
:- 以非阻塞模式打开文件。
- 读写操作不会阻塞进程,适用于需要非阻塞操作的情况(如管道和套接字)。
-
O_SYNC
:- 以同步模式打开文件。
- 写入操作会在返回前确保数据被写入磁盘,适用于对数据持久性要求高的场景。
-
O_DSYNC
:
- 以同步模式打开文件。不包括文件的元数据(如修改时间等)
- 由于 O_DSYNC 不涉及文件的元数据同步,它的性能开销通常低于 O_SYNC。这使得 O_DSYNC 更适合对数据持久性要求高但对元数据一致性要求相对较低的场景。
文件权限(mode)
当使用 O_CREAT
创建文件时,还需要指定文件权限(mode)。这是一个三位八进制数,表示文件的权限。例如:
0666
:文件的所有者、组和其他用户都有读写权限。0644
:文件的所有者有读写权限,而组和其他用户只有读权限。0755
:文件的所有者有读、写和执行权限,而组和其他用户只有读和执行权限。
权限模式由三个部分组成,分别表示文件的用户、组和其他用户的权限:
- 用户权限(Owner permissions) :前两位(如
6
表示读写权限,4
表示读权限)。 - 组权限(Group permissions):中间两位。
- 其他权限(Other permissions):最后两位。
write
write
函数用于向文件写入数据。它在<unistd.h>
头文件中定义。
c
#include <unistd.h>
ssize_t write(int fd, const void *buf, size_t count);
fd
:文件描述符,通过open
函数获得。buf
:指向要写入数据的内存区域的指针。count
:要写入的字节数。
返回值:
- 成功时返回实际写入的字节数。
- 失败时返回
-1
,并设置errno
。
read
read
函数用于从文件中读取数据。它同样在<unistd.h>
头文件中定义。
c
#include <unistd.h>
ssize_t read(int fd, void *buf, size_t count);
fd
:文件描述符,通过open
函数获得。buf
:指向用来存储读取数据的内存区域的指针。count
:要读取的字节数。
返回值:
- 成功时返回实际读取的字节数(可能小于
count
)。 - 返回
0
表示文件末尾。 - 失败时返回
-1
,并设置errno
。
lseek
lseek
是一个用于调整文件描述符的文件偏移量的系统调用。它可以在文件中设置读写操作的位置。以下是 lseek
的基本用法和参数说明:
c
off_t lseek(int fd, off_t offset, int whence);
fd
:文件描述符,通常由open
系统调用返回。offset
:新的偏移量值,具体含义取决于whence
参数。whence
:指定偏移量的起始位置,可以是以下三个常量之一:SEEK_SET
:文件的起始位置。SEEK_CUR
:文件当前的位置。SEEK_END
:文件的末尾位置。
返回值
- 成功时,
lseek
返回新的文件偏移量。 - 失败时,返回
-1
并设置errno
以指示错误原因。
综合示例
c
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
int main() {
int fd = open("out.txt", O_RDWR | O_CREAT | O_TRUNC, 0644);
if (fd < 0) {
perror("open");
exit(EXIT_FAILURE);
}
// 写入数据
const char *message = "Hello World";
ssize_t bytesWritten = write(fd, message, strlen(message));
if (bytesWritten < 0) {
perror("write");
close(fd);
exit(EXIT_FAILURE);
}
// 将文件描述符 fd 的偏移量设置到文件的开始位置
if (lseek(fd, 0, SEEK_SET) < 0) {
perror("lseek");
close(fd);
exit(EXIT_FAILURE);
}
// 读取数据
char buffer[20];
ssize_t bytesRead = read(fd, buffer, sizeof(buffer) - 1);
if (bytesRead < 0) {
perror("read");
close(fd);
exit(EXIT_FAILURE);
}
// 字符串要添加终止符
buffer[bytesRead] = '\0';
printf("%s\n", buffer);
// 关闭文件
close(fd);
return 0;
}