pwritev系统调用及示例

pwritev 函数

1. 函数介绍

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

2. 函数原型

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

3. 功能

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

4. 参数

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

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

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

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

5. 返回值

  • 成功: 返回实际写入的总字节数

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

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

  • writev: 基本的聚集写入函数

  • pwrite: 单缓冲区定位写入函数

  • preadv: 对应的读取函数

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
#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>

/**
* 使用pwritev进行聚集写入
*/
int demo_pwritev_basic() {
int fd;
struct iovec iov&#91;3];
ssize_t total_bytes;

// 准备要写入的数据
char data1&#91;] = "First part of the message\n";
char data2&#91;] = "Second part with more content ";
char data3&#91;] = "and final part.\n";

printf("=== pwritev 基本使用示例 ===\n");
printf("准备写入的数据:\n");
printf("数据1: %s", data1);
printf("数据2: %s", data2);
printf("数据3: %s", data3);

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

// 设置iovec数组
iov&#91;0].iov_base = data1;
iov&#91;0].iov_len = strlen(data1);
iov&#91;1].iov_base = data2;
iov&#91;1].iov_len = strlen(data2);
iov&#91;2].iov_base = data3;
iov&#91;2].iov_len = strlen(data3);

// 使用pwritev写入数据
total_bytes = pwritev(fd, iov, 3, 0);
if (total_bytes == -1) {
perror("pwritev 失败");
close(fd);
return -1;
}

printf("\npwritev 写入了 %zd 字节到文件\n", total_bytes);

// 读取并验证写入的数据
char buffer&#91;256];
lseek(fd, 0, SEEK_SET);
ssize_t bytes_read = read(fd, buffer, sizeof(buffer) - 1);
if (bytes_read > 0) {
buffer&#91;bytes_read] = '\0';
printf("\n文件内容验证:\n%s", buffer);
}

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

/**
* 演示pwritev写入HTTP响应头
*/
int demo_pwritev_http_response() {
int fd;
struct iovec iov&#91;4];
ssize_t total_bytes;

printf("\n=== pwritev HTTP响应示例 ===\n");

// HTTP响应的各个部分
char status_line&#91;] = "HTTP/1.1 200 OK\r\n";
char headers&#91;] = "Content-Type: text/html\r\n"
"Content-Length: 25\r\n"
"Connection: close\r\n";
char separator&#91;] = "\r\n";
char body&#91;] = "<html><body>Hello</body></html>";

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

// 设置iovec数组
iov&#91;0].iov_base = status_line;
iov&#91;0].iov_len = strlen(status_line);
iov&#91;1].iov_base = headers;
iov&#91;1].iov_len = strlen(headers);
iov&#91;2].iov_base = separator;
iov&#91;2].iov_len = strlen(separator);
iov&#91;3].iov_base = body;
iov&#91;3].iov_len = strlen(body);

// 一次性写入完整的HTTP响应
total_bytes = pwritev(fd, iov, 4, 0);
if (total_bytes == -1) {
perror("pwritev 写入HTTP响应失败");
close(fd);
return -1;
}

printf("成功写入HTTP响应,共 %zd 字节\n", total_bytes);

// 显示生成的HTTP响应
char buffer&#91;512];
lseek(fd, 0, SEEK_SET);
ssize_t bytes_read = read(fd, buffer, sizeof(buffer) - 1);
if (bytes_read > 0) {
buffer&#91;bytes_read] = '\0';
printf("\n生成的HTTP响应:\n%s", buffer);
}

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

int main() {
if (demo_pwritev_basic() == 0) {
demo_pwritev_http_response();
printf("\n=== pwritev 使用总结 ===\n");
printf("优点:一次系统调用写入多个缓冲区,提高效率\n");
printf("适用场景:网络协议数据发送,日志记录,配置文件更新\n");
}
return 0;
}

pwritev系统调用及示例-CSDN博客

data-ad-format="auto" data-full-width-responsive="true">