preadv1系统调用及示例

preadv 函数

data-ad-format="fluid" data-ad-layout-key="-7k+ex-4a-9w+4a">

preadv 是 pread 的分散读取版本,它允许一次性从文件的指定位置读取数据到多个不连续的缓冲区中。这是分散/聚集I/O操作的一部分。(https://www.calcguide.tech/2025/08/16/preadv1系统调用及示例/)

1. 函数介绍

preadv 是 pread 的分散读取版本,它允许一次性从文件的指定位置读取数据到多个不连续的缓冲区中。这是分散/聚集I/O操作的一部分。

2. 函数原型

1
2
3
4
#define _GNU_SOURCE
#include <sys/uio.h>
ssize_t preadv(int fd, const struct iovec *iov, int iovcnt, off_t offset);

3. 功能

从文件描述符 fd 指定的文件中,从 offset 位置开始读取数据到由 iov 描述的多个缓冲区中。该操作不会改变文件的当前读写位置。

4. 参数

  • int fd: 文件描述符,必须是已打开的文件

  • *const struct iovec iov: iovec结构体数组,描述多个缓冲区

  • int iovcnt: iov数组中的元素个数

  • off_t offset: 文件中的偏移量(从文件开始处计算)

5. 返回值

  • 成功: 返回实际读取的总字节数

  • 文件末尾: 返回0

  • 失败: 返回-1,并设置errno

6. 相似函数,或关联函数

  • readv: 基本的分散读取函数

  • pread: 单缓冲区定位读取函数

  • pwritev: 对应的写入函数

7. 示例代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
#define _GNU_SOURCE
#include <sys/uio.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>

/**
* 使用preadv进行分散读取
*/
int demo_preadv_basic() {
int fd;
struct iovec iov&#91;3];
char buf1&#91;20], buf2&#91;15], buf3&#91;30];
ssize_t total_bytes;

// 创建测试文件
fd = open("test_preadv.txt", O_CREAT | O_WRONLY | O_TRUNC, 0644);
if (fd == -1) {
perror("创建测试文件失败");
return -1;
}

// 写入测试数据
const char *test_data = "This is a long test string for preadv demonstration purposes.";
write(fd, test_data, strlen(test_data));
close(fd);

// 打开文件进行分散读取
fd = open("test_preadv.txt", O_RDONLY);
if (fd == -1) {
perror("打开文件失败");
return -1;
}

printf("=== preadv 基本使用示例 ===\n");
printf("测试数据: %s\n", test_data);
printf("数据长度: %zu 字节\n\n", strlen(test_data));

// 设置iovec数组
iov&#91;0].iov_base = buf1;
iov&#91;0].iov_len = sizeof(buf1) - 1;
iov&#91;1].iov_base = buf2;
iov&#91;1].iov_len = sizeof(buf2) - 1;
iov&#91;2].iov_base = buf3;
iov&#91;2].iov_len = sizeof(buf3) - 1;

// 从偏移量0开始分散读取
total_bytes = preadv(fd, iov, 3, 0);
if (total_bytes == -1) {
perror("preadv 失败");
close(fd);
return -1;
}

printf("preadv 读取了 %zd 字节到3个缓冲区:\n", total_bytes);

// 添加字符串结束符并显示结果
buf1&#91;iov&#91;0].iov_len] = '\0';
buf2&#91;iov&#91;1].iov_len] = '\0';
buf3&#91;iov&#91;2].iov_len] = '\0';

printf("缓冲区1 (%zu字节): %s\n", iov&#91;0].iov_len, buf1);
printf("缓冲区2 (%zu字节): %s\n", iov&#91;1].iov_len, buf2);
printf("缓冲区3 (%zu字节): %s\n", iov&#91;2].iov_len, buf3);

close(fd);
unlink("test_preadv.txt");
return 0;
}

/**
* 演示preadv读取结构体数据
*/
struct Person {
int id;
char name&#91;20];
float score;
};

int demo_preadv_struct() {
int fd;
struct iovec iov&#91;3];
struct Person person = {1001, "Alice Johnson", 95.5};
int read_id;
char read_name&#91;20];
float read_score;

printf("\n=== preadv 读取结构体数据示例 ===\n");

// 创建包含结构体数据的文件
fd = open("person_data.bin", O_CREAT | O_WRONLY | O_TRUNC, 0644);
if (fd == -1) {
perror("创建数据文件失败");
return -1;
}

write(fd, &person, sizeof(person));
close(fd);

// 使用preadv分别读取结构体的各个字段
fd = open("person_data.bin", O_RDONLY);
if (fd == -1) {
perror("打开数据文件失败");
return -1;
}

// 设置iovec读取结构体的各个部分
iov&#91;0].iov_base = &read_id;
iov&#91;0].iov_len = sizeof(read_id);
iov&#91;1].iov_base = read_name;
iov&#91;1].iov_len = sizeof(read_name);
iov&#91;2].iov_base = &read_score;
iov&#91;2].iov_len = sizeof(read_score);

ssize_t bytes_read = preadv(fd, iov, 3, 0);
if (bytes_read == -1) {
perror("preadv 读取结构体失败");
close(fd);
return -1;
}

printf("读取了 %zd 字节的结构体数据:\n", bytes_read);
printf("ID: %d\n", read_id);
printf("Name: %s\n", read_name);
printf("Score: %.1f\n", read_score);

close(fd);
unlink("person_data.bin");
return 0;
}

int main() {
if (demo_preadv_basic() == 0) {
demo_preadv_struct();
printf("\n=== preadv 使用总结 ===\n");
printf("优点:一次系统调用读取多个缓冲区,减少系统调用开销\n");
printf("适用场景:读取结构化数据,协议解析,网络数据包处理\n");
}
return 0;
}
data-ad-format="auto" data-full-width-responsive="true">