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

`read`系统调用示例

read。这个函数是与 openwrite 配合使用,用于从文件描述符指向的文件中读取数据。


1. 函数介绍

read 是一个 Linux 系统调用,它的主要作用是从指定的文件描述符(file descriptor)所关联的文件、管道、套接字等输入流中读取数据,并将其存放到程序提供的缓冲区中。你可以把它想象成从一个“数据源”里“拿出”一些字节放到你自己的“篮子”(缓冲区)里。


2. 函数原型

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

3. 功能

尝试从文件描述符 fd 指向的文件或资源中读取最多 count 个字节的数据,并将这些数据存储到从 buf 指向的内存地址开始的缓冲区中。


4. 参数

  • int fd: 这是文件描述符 (file descriptor)。它是一个非负整数,由 opencreatsocket 等系统调用成功执行后返回,用以标识一个已打开的文件或资源。
  • void *buf: 这是一个指向缓冲区的指针。读取到的数据将被存放到从这个地址开始的内存空间中。你需要确保这个缓冲区至少有 count 个字节的空间。
  • size_t count: 这是你希望读取的最大字节数。函数不会读取超过 count 个字节的数据。

5. 返回值

read 函数返回实际读取到的字节数,这个数可能小于或等于请求的 count

  • 成功时:
    • 返回实际读取到的字节数 (0 <= 返回值 <= count)。
    • 如果返回值为 0,通常表示已经到达文件末尾 (End Of File, EOF) 或者没有更多数据可读(例如从管道或网络套接字读取时对端已关闭)。
  • 出错时:
    • 返回 -1,并设置全局变量 errno 来指示具体的错误类型(例如 EAGAINEBADFEFAULT 等)。

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

  • pread: 类似于 read,但它允许你在一次调用中同时指定要读取的文件描述符、缓冲区、读取字节数以及文件内的偏移量。它不会改变文件的当前偏移量。
  • readv: 允许你将数据读入到多个不连续的缓冲区(一个 iovec 数组)中,这在处理结构化数据时很有用。
  • write: 与 read 相反,用于将数据写入到文件描述符指向的文件或资源中。
  • open: 通常在调用 read 之前使用,用来获取文件描述符。

7. 示例代码

示例 1:从普通文件读取内容
#include <unistd.h>  // read, write, close
#include <fcntl.h>   // open, O_RDONLY
#include <stdio.h>   // perror, printf
#include <stdlib.h>  // exit
#include <errno.h>   // errno#define BUFFER_SIZE 1024int main() {int fd;                 // 文件描述符char buffer[BUFFER_SIZE]; // 用于存储读取数据的缓冲区ssize_t bytes_read;     // 实际读取的字节数// 1. 打开一个文件以供读取 (假设当前目录下有名为 "example.txt" 的文件)fd = open("example.txt", O_RDONLY);if (fd == -1) {perror("Error opening file"); // 打印错误信息exit(EXIT_FAILURE);}printf("File opened successfully with fd: %d\n", fd);// 2. 循环读取文件内容,直到文件末尾while ((bytes_read = read(fd, buffer, BUFFER_SIZE)) > 0) {// 3. 将读取到的内容写入标准输出 (屏幕)// 注意:这里没有处理 write 可能只写入部分数据的情况,// 在实际应用中可能需要循环确保所有数据都被写入。if (write(STDOUT_FILENO, buffer, bytes_read) != bytes_read) {perror("Error writing to stdout");close(fd); // 出错也要记得关闭文件exit(EXIT_FAILURE);}// 可选:打印本次读取了多少字节// printf("Read %zd bytes\n", bytes_read);}// 4. 检查 read 是否因错误而返回if (bytes_read == -1) {perror("Error reading file");close(fd);exit(EXIT_FAILURE);}// 5. 关闭文件描述符if (close(fd) == -1) {perror("Error closing file");exit(EXIT_FAILURE);}printf("\nFinished reading file.\n");return 0;
}

代码解释:

  1. 定义了缓冲区大小 BUFFER_SIZE
  2. 使用 open() 以只读模式 (O_RDONLY) 打开名为 example.txt 的文件。如果失败,perror() 会打印具体错误原因,程序退出。
  3. 进入 while 循环,调用 read(fd, buffer, BUFFER_SIZE)。它会尝试读取最多 1024 个字节。
  4. 如果 read 返回大于 0 的值,说明读到了数据。然后使用 write() 将这些数据写到标准输出 (STDOUT_FILENO,其值为 1)。
  5. 循环继续,直到 read 返回 0(EOF)。
  6. 检查 read 是否返回 -1(错误)。
  7. 最后,使用 close() 关闭文件描述符,释放资源。
示例 2:从标准输入读取一行

这个例子演示如何从键盘(标准输入)读取用户输入的一行文本。

#include <unistd.h>  // read
#include <stdio.h>   // perror, printf
#include <stdlib.h>  // exit#define MAX_INPUT_SIZE 256int main() {char input_buffer[MAX_INPUT_SIZE];ssize_t bytes_read;int i;printf("Enter a line of text (max %d chars): ", MAX_INPUT_SIZE - 1);// 从标准输入 (STDIN_FILENO=0) 读取数据bytes_read = read(STDIN_FILENO, input_buffer, MAX_INPUT_SIZE - 1);if (bytes_read == -1) {perror("Error reading from stdin");exit(EXIT_FAILURE);} else if (bytes_read == 0) {printf("No data read (EOF on stdin?)\n");} else {// 寻找换行符 \n,将其替换为字符串结束符 \0// 这样可以方便地将输入作为 C 字符串处理for (i = 0; i < bytes_read; ++i) {if (input_buffer[i] == '\n') {input_buffer[i] = '\0';break;}}// 如果没有找到 \n (例如输入达到缓冲区最大限制),手动添加 \0if (i == bytes_read) {input_buffer[bytes_read] = '\0';}printf("You entered: %s\n", input_buffer);// 注意:实际读取的字符数可能比 strlen(input_buffer) 多1(因为 \n 被替换了)printf("Number of bytes read (including \\n if present): %zd\n", bytes_read);}return 0;
}

代码解释:

  1. 提示用户输入。
  2. 调用 read(STDIN_FILENO, ...) 从键盘读取最多 MAX_INPUT_SIZE - 1 个字符(留一个位置给可能添加的 \0)。
  3. 检查返回值:-1 表示错误,0 表示 EOF,正数表示读取的字节数。
  4. 为了方便打印,代码查找读入的缓冲区中的换行符 \n 并将其替换为字符串结束符 \0
  5. 使用 printf 打印处理后的字符串和实际读取的字节数。

理解 read 函数的关键在于掌握文件描述符的概念以及如何处理其返回值(特别是区分读到数据、到达文件末尾和发生错误的情况)。

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

相关文章:

  • java每日精进 7.26【流程设计5.0(中间事件+结束事件)】
  • 检索召回率优化探究一:基于 LangChain 0.3集成 Milvus 2.5向量数据库构建的智能问答系统
  • 全球化2.0 | 云轴科技ZStack亮相阿里云印尼国有企业CXO专家活动
  • FreeMarker模板引擎
  • Windows Server系统安装JDK,一直卡在“应用程序正在为首次使用作准备,请稍候”
  • Vibe Coding | 技术让我们回归了创造的本质
  • hot100-每日温度
  • 字符串缓冲区和正则表达式
  • I/O 软件层次结构
  • 分布式数据库的分布透明性详解
  • 【前端】Vue 3 课程选择组件开发实战:从设计到实现
  • 如何从自定义或本地仓库安装 VsCode 扩展
  • 手写PPO_clip(FrozenLake环境)
  • 统计学08:概率分布
  • 面试实战,问题十二,Spring Boot接收和处理HTTP请求的详细原理,怎么回答
  • AI 编程工具 Trae 重要的升级。。。
  • 二维数组相关学习
  • 栈----3.字符串解码
  • 论文阅读-RaftStereo
  • 2025中国GEO优化白皮书:AI搜索优化趋势+行业数据报告
  • 应急控制HMI的“黄金10秒”设计:紧急场景下的操作路径极速简化技术
  • 嵌入式硬件篇---有线串口通信问题解决
  • PHP语法高级篇(六):面向对象编程
  • MyBatis-Plus 核心注解详解:从表映射到逻辑删除的全方位指南
  • C++/CLI vs 标准 C++ vs C# 语法对照手册
  • 9.3 快速傅里叶变换
  • 深度解析 noisereduce:开源音频降噪库实践
  • 深入理解Redission释放锁过程
  • Blender入门笔记(一)
  • 利用RAII与析构函数避免C++资源泄漏