pwritev 函数
1. 函数介绍
pwritev
是 pwrite
的聚集写入版本,它允许一次性将多个不连续缓冲区中的数据写入到文件的指定位置。这是分散/聚集I/O操作的写入部分。
2. 函数原型
#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. 示例代码
#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[3];
ssize_t total_bytes;
// 准备要写入的数据
char data1[] = "First part of the message\n";
char data2[] = "Second part with more content ";
char data3[] = "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[0].iov_base = data1;
iov[0].iov_len = strlen(data1);
iov[1].iov_base = data2;
iov[1].iov_len = strlen(data2);
iov[2].iov_base = data3;
iov[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[256];
lseek(fd, 0, SEEK_SET);
ssize_t bytes_read = read(fd, buffer, sizeof(buffer) - 1);
if (bytes_read > 0) {
buffer[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[4];
ssize_t total_bytes;
printf("\n=== pwritev HTTP响应示例 ===\n");
// HTTP响应的各个部分
char status_line[] = "HTTP/1.1 200 OK\r\n";
char headers[] = "Content-Type: text/html\r\n"
"Content-Length: 25\r\n"
"Connection: close\r\n";
char separator[] = "\r\n";
char body[] = "<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[0].iov_base = status_line;
iov[0].iov_len = strlen(status_line);
iov[1].iov_base = headers;
iov[1].iov_len = strlen(headers);
iov[2].iov_base = separator;
iov[2].iov_len = strlen(separator);
iov[3].iov_base = body;
iov[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[512];
lseek(fd, 0, SEEK_SET);
ssize_t bytes_read = read(fd, buffer, sizeof(buffer) - 1);
if (bytes_read > 0) {
buffer[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;
}