当前位置: 首页 > news >正文

write`系统调用

我们来介绍与 readopen 紧密配合使用的 write 函数。如果说 read 是从文件描述符“拿”数据,那么 write 就是向文件描述符“放”数据。


1. 函数介绍

write 是一个 Linux 系统调用,用于将数据从程序的缓冲区写入到由文件描述符 fd 指定的文件、管道、套接字或其他输出流中。它是程序向外部(如文件、屏幕、网络)发送数据的基本方式之一。


2. 函数原型

#include <unistd.h>ssize_t write(int fd, const void *buf, size_t count);

3. 功能

尝试将 count 个字节的数据从 buf 指向的缓冲区写入到文件描述符 fd 所关联的文件或资源中。


4. 参数

  • int fd: 这是目标文件描述符。它标识了数据要写入的目标,比如通过 open 打开的文件、标准输出 (STDOUT_FILENO)、标准错误 (STDERR_FILENO) 或一个网络套接字等。
  • const void *buf: 这是一个指向包含待写入数据的缓冲区的指针。由于数据是从这个缓冲区读取并写出去的,所以指针被声明为 const,表明函数不会修改这块内存中的数据。
  • size_t count: 这是要写入的字节数。函数会尝试写入从 buf 开始的 count 个字节。

5. 返回值

write 函数返回实际成功写入的字节数。

  • 成功时:
    • 返回实际写入的字节数 (0 <= 返回值 <= count)。
    • 在阻塞模式下,通常返回值会等于 count。但在某些情况下(如写入管道或网络套接字时缓冲区满),返回值可能小于 count。这时,程序通常需要循环调用 write 来写入剩余的数据。
  • 出错时:
    • 返回 -1,并设置全局变量 errno 来指示具体的错误类型(例如 EAGAINEBADFEFAULTENOSPC 等)。

重要提示: 绝对不能仅仅通过检查 write 的返回值是否为 -1 来判断写操作是否完全成功。必须检查返回值是否等于请求写入的字节数 count,或者在返回值小于 count 时采取相应措施(如循环写入)。


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

  • pwrite: 类似于 write,但它允许你在一次调用中同时指定要写入的文件描述符、缓冲区、写入字节数以及文件内的偏移量。它不会改变文件的当前偏移量。
  • writev: 允许你将多个不连续缓冲区(一个 iovec 数组)中的数据写入到文件描述符中,这对于需要拼接发送多个数据块的场景非常有用。
  • read: 与 write 相反,用于从文件描述符读取数据。
  • open: 通常在调用 write 之前使用,用来获取要写入文件的文件描述符。

7. 示例代码

示例 1:将数据写入文件

这个例子演示如何创建(或截断)一个文件,并将一些文本数据写入其中。

#include <unistd.h>  // write, close
#include <fcntl.h>   // open, O_WRONLY, O_CREAT, O_TRUNC
#include <stdio.h>   // perror, printf
#include <stdlib.h>  // exit
#include <string.h>  // strlen
#include <errno.h>   // errnoint main() {int fd;                    // 文件描述符const char *message = "Hello, Linux System Programming!\n";size_t message_len = strlen(message); // 获取要写入的字节数ssize_t bytes_written;    // 实际写入的字节数// 1. 打开(或创建)一个文件用于写入// O_WRONLY: 只写模式// O_CREAT: 如果文件不存在则创建// O_TRUNC: 如果文件存在,则截断(清空)它// 0644 是新创建文件的权限 (所有者读写,组和其他用户只读)fd = open("output.txt", O_WRONLY | O_CREAT | O_TRUNC, 0644);if (fd == -1) {perror("Error opening/creating file");exit(EXIT_FAILURE);}printf("File 'output.txt' opened/created successfully with fd: %d\n", fd);// 2. 调用 write 将数据写入文件bytes_written = write(fd, message, message_len);// 3. 检查 write 的返回值if (bytes_written == -1) {perror("Error writing to file");close(fd); // 出错也要记得关闭文件exit(EXIT_FAILURE);} else if ((size_t)bytes_written != message_len) {// 检查是否所有数据都被写入 (在简单场景下通常如此,但好习惯是检查)fprintf(stderr, "Warning: Only %zd of %zu bytes written to file.\n", bytes_written, message_len);// 在实际应用中,可能需要循环 write 来处理这种情况} else {printf("Successfully wrote %zd bytes to 'output.txt'.\n", bytes_written);}// 4. 关闭文件描述符if (close(fd) == -1) {perror("Error closing file");exit(EXIT_FAILURE);}printf("File closed. Check 'output.txt' for the content.\n");return 0;
}

代码解释:

  1. 定义要写入的字符串 message 和其长度 message_len
  2. 使用 open() 以只写模式 (O_WRONLY) 打开或创建 output.txt 文件。如果文件不存在则创建 (O_CREAT),如果存在则清空 (O_TRUNC)。权限设置为 0644
  3. 调用 write(fd, message, message_len) 尝试将整个消息写入文件。
  4. 检查 write 的返回值:-1 表示错误;如果返回值不等于 message_len,则表示未完全写入(在此简单场景下不太可能发生,但展示了检查的必要性);否则表示成功写入。
  5. 最后,使用 close() 关闭文件描述符。
示例 2:向标准错误输出写入错误信息

这个例子展示了如何使用 write 向标准错误 (STDERR_FILENO) 写入信息,这通常用于输出错误或诊断信息,与标准输出分开。

#include <unistd.h>  // write
#include <string.h>  // strlenint main() {const char *error_msg = "An error occurred in the program.\n";// 直接向标准错误 (文件描述符 2) 写入错误信息// 注意:这里也没有处理 write 可能部分写入的情况,// 对于短消息写入 stderr 通常可以假设一次性成功,// 但在严格要求下仍需检查返回值。write(STDERR_FILENO, error_msg, strlen(error_msg));return 0; // 程序正常退出,但 stderr 上有错误信息
}

代码解释:

  1. 定义错误信息字符串。
  2. 直接调用 write(STDERR_FILENO, error_msg, strlen(error_msg)) 将错误信息写入标准错误输出。STDERR_FILENO 是预定义的常量,值为 2。

理解 write 函数的关键在于记住它只是“尝试”写入指定数量的字节,并且总是需要检查返回值来确认操作结果和实际写入的字节数。

http://www.dtcms.com/a/299761.html

相关文章:

  • 字节跳动正式开源AI智能体开发平台Coze
  • LeetCode——1957. 删除字符使字符串变好
  • 1.安装anaconda详细步骤(含安装截图)
  • Typecho插件开发实战:构建专业级访问日志系统
  • ESP32-idf学习(五)esp32C3移植lvgl①
  • 贝叶斯决策论
  • Spring AI MCP 客户端
  • Django+celery异步:拿来即用,可移植性高
  • SSSM框架相关问题总结
  • 拒绝SQL恐惧:用Python+pyqt打造Excel数据库查询系统
  • [Java恶补day47] 整理模板·考点十【二叉树层序遍历】
  • 快速入门Linux操作系统(一)
  • LeetCode 面试经典 150_数组/字符串_删除有序数组中的重复项(3_26_C++_简单)
  • RabbitMQ--消息丢失问题及解决
  • 是德科技 | AI上车后,这条“高速公路”如何畅通?
  • 如何高效合并音视频文件(时间短消耗资源少)(二)
  • 计网-TCP可靠传输
  • 周末小游戏推荐,离线也能畅玩
  • 阿里云对象存储OSS(Object Storage Service)全面解析
  • 如何解决pip安装报错ModuleNotFoundError: No module named ‘ipython’问题
  • 【计算机组成原理】第一章:计算机系统概述
  • GO 从入门到精通
  • STL——vector
  • GO 从入门到精通2
  • MyBatis-Plus 通用 Service
  • J2EE模式---表现层集成模式
  • MyBatis Plus 对数据表常用注解
  • 进阶数据结构:用红黑树实现封装map和set
  • Sql server查询汇总补缺月份
  • 【NLP舆情分析】基于python微博舆情分析可视化系统(flask+pandas+echarts) 视频教程 - 热词评论查询功能实现