Windows 文件读写函数 ReadFile()WriteFile() 的阻塞与非阻塞操作详解(含完整C语言示例)

在 Windows 平台进行文件或设备(如串口、管道)编程时,ReadFile()WriteFile() 是最常用的两个 API 函数。它们既可以以阻塞方式运行,也可以通过设置标志实现非阻塞方式运行。本文将详细讲解这两种模式的区别,并提供完整的 C 语言示例代码。


一、概述:ReadFile()WriteFile() 简介

这两个函数定义在 windows.h 头文件中:

BOOL ReadFile(HANDLE       hFile,LPVOID       lpBuffer,DWORD        nNumberOfBytesToRead,LPDWORD      lpNumberOfBytesRead,LPOVERLAPPED lpOverlapped
);BOOL WriteFile(HANDLE       hFile,LPCVOID      lpBuffer,DWORD        nNumberOfBytesToWrite,LPDWORD      lpNumberOfBytesWritten,LPOVERLAPPED lpOverlapped
);
  • hFile:文件或设备的句柄。
  • lpBuffer:数据缓冲区地址。
  • nNumberOfBytesTo(Read/Write):要读写的字节数。
  • lpNumberOfBytes(Read/Written):实际读写的数据长度。
  • lpOverlapped:重叠结构指针。为 NULL 表示同步(阻塞)操作;否则表示异步(非阻塞)操作。

二、阻塞操作 vs 非阻塞操作

特性阻塞操作(默认)非阻塞操作(异步)
是否等待完成是,调用线程会被挂起直到操作完成否,函数立即返回,操作由系统后台完成
是否需要 OVERLAPPED 结构
是否支持事件通知可结合事件对象进行通知
是否支持 I/O 完成端口
CPU 使用率较低(等待期间休眠)较高(需主动轮询或使用回调)
实现复杂度简单复杂

三、阻塞方式示例

✅ 示例1:阻塞方式读写文件

#include <windows.h>
#include <stdio.h>int main() {HANDLE hFile = CreateFile(TEXT("testfile.txt"),GENERIC_READ | GENERIC_WRITE,0,NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL);if (hFile == INVALID_HANDLE_VALUE) {printf("CreateFile failed (%d)\n", GetLastError());return 1;}const char* buffer = "Hello, World!";DWORD bytesWritten;// 写入文件(阻塞)if (!WriteFile(hFile, buffer, strlen(buffer), &bytesWritten, NULL)) {printf("WriteFile failed (%d)\n", GetLastError());CloseHandle(hFile);return 1;}printf("Wrote %d bytes\n", bytesWritten);// 移动文件指针到开头SetFilePointer(hFile, 0, NULL, FILE_BEGIN);char readBuffer[256];DWORD bytesRead;// 读取文件(阻塞)if (!ReadFile(hFile, readBuffer, sizeof(readBuffer), &bytesRead, NULL)) {printf("ReadFile failed (%d)\n", GetLastError());CloseHandle(hFile);return 1;}readBuffer[bytesRead] = '\0';  // 添加字符串结束符printf("Read: %s\n", readBuffer);CloseHandle(hFile);return 0;
}

📌 编译命令(MinGW / GCC):

gcc -o blocking_example blocking_example.c -mwindows

四、非阻塞方式示例(异步操作)

使用 OVERLAPPED 结构和事件对象可以实现非阻塞读写。下面是一个完整的异步读取示例:

✅ 示例2:非阻塞方式读取文件(异步 + 事件通知)

#include <windows.h>
#include <stdio.h>int main() {HANDLE hFile = CreateFile(TEXT("testfile.txt"),GENERIC_READ,0,NULL,OPEN_EXISTING,FILE_FLAG_OVERLAPPED,  // 设置为异步操作NULL);if (hFile == INVALID_HANDLE_VALUE) {printf("CreateFile failed (%d)\n", GetLastError());return 1;}char buffer[256];DWORD bytesRead;OVERLAPPED overlapped = {0};overlapped.Offset = 0;overlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);  // 创建事件// 异步读取BOOL result = ReadFile(hFile, buffer, sizeof(buffer), &bytesRead, &overlapped);if (!result && GetLastError() != ERROR_IO_PENDING) {printf("ReadFile error (%d)\n", GetLastError());CloseHandle(hFile);return 1;}printf("Waiting for asynchronous read to complete...\n");// 等待事件触发(可替换为 WaitForMultipleObjects 或其他机制)WaitForSingleObject(overlapped.hEvent, INFINITE);// 获取最终结果if (!GetOverlappedResult(hFile, &overlapped, &bytesRead, FALSE)) {printf("GetOverlappedResult failed (%d)\n", GetLastError());} else {buffer[bytesRead] = '\0';printf("Async read completed: %s\n", buffer);}CloseHandle(overlapped.hEvent);CloseHandle(hFile);return 0;
}

📌 编译命令:

gcc -o async_read async_read.c -mwindows

五、总结对比

功能阻塞方式非阻塞方式(异步)
是否立即返回
是否适合大量并发
是否支持事件通知
是否需要处理线程阻塞不需要需要配合事件、线程池或 I/O 完成端口
适用场景简单文件读写、调试高性能网络服务、串口通信、异步I/O

六、扩展建议

  • 对于高性能服务器程序,建议结合 I/O 完成端口(IOCP) 使用异步模型。
  • 如果需要同时处理多个异步请求,应使用 线程池WaitForMultipleObjects
  • 对于串口、管道等设备通信,通常推荐使用异步模式提升响应能力。

七、结语

Windows 提供了灵活的文件和设备读写接口,开发者可以根据需求选择阻塞模式非阻塞异步模式。理解两者的区别及使用方法,是编写高效 Windows 应用的关键一步。希望本篇博客能帮助你更好地掌握 ReadFile()WriteFile() 的使用技巧!


研究学习不易,点赞易。
工作生活不易,收藏易,点收藏不迷茫 :)


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/diannao/87683.shtml
繁体地址,请注明出处:http://hk.pswp.cn/diannao/87683.shtml
英文地址,请注明出处:http://en.pswp.cn/diannao/87683.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Singularity 安装

Singularity 是什么? 核心功能:用于创建/运行容器(将应用+依赖打包的独立环境)。 与 Docker 的区别:专为 HPC(高性能计算)设计,无需后台守护进程,支持非 root 运行容器(但安装本身需 root 权限)。 适用于在具有 root 权限的计算机上从源代码安装 Singularity。…

辩证视角下 “辫子戏” 的文化反思与价值重构

前阵子播出的《人生若如初见》刻意美化晚清封建统治阶级&#xff0c;淡化甚至掩盖清政府闭关锁国、丧权辱国、残酷压迫民众等历史真相&#xff0c;将本应批判反思的腐朽统治包装成值得歌颂的对象&#xff1b;在历史叙事上&#xff0c;或通过虚构、篡改重要历史事件和人物形象&a…

MCP-server

&#x1f4a1; 说明&#xff1a;该模块是 MCP 服务器的 数据中继层&#xff0c;确保安全高效地从分布式来源获取模型及其上下文&#xff0c;适用于边缘计算和联邦学习场景。若要查看完整代码&#xff0c;建议直接访问 GitHub 链接

第3讲、LangChain性能优化:上下文缓存与流式响应实战指南

目录 概述上下文缓存优化流式响应优化复杂对话场景性能优化用户体验优化策略完整实现示例性能监控与调优总结 概述 在复杂对话场景中&#xff0c;大型语言模型面临着响应延迟、重复计算、上下文管理等挑战。本文将详细介绍如何通过LangChain的上下文缓存和流式响应功能来优化…

http中GET和POST、PUT之间的区别

在HTTP协议中&#xff0c;GET、POST和PUT是三种最常用的请求方法&#xff0c;它们的主要区别如下&#xff1a; 1. GET 用途&#xff1a;用于请求资源&#xff08;查询数据&#xff09;&#xff0c;不应修改服务器状态。 参数传递&#xff1a;通过URL的查询字符串&#xff08;…

埃夫特各种系列机器人运动学建模、轨迹规划和工作空间求解

要求&#xff1a; 1.理论分析 1.1 正向运动学&#xff1a;根据D-H法完成机器人的正向运动学&#xff08;数学建模后基于Matlab计算公式&#xff09;&#xff1b; 1.2 工作空间分析&#xff1a;根据正向运动学结果&#xff0c;运用 MATLAB进行工作空间分析&#xff0c;完成工…

VUE3 路由的跳转方法

Routerlink跳转方法 name属性对应了路由文件配置的name path属性对应了路由的路径 <RouterLink to"/login">点击跳转登陆</RouterLink> <RouterLink :to"{name:login}">点击跳转登陆</RouterLink> <RouterLink :to"{pat…

数据库中间件ShardingSphere5

一、高性能架构模式 数据库集群&#xff0c;第一种方式“读写分离”&#xff0c;第二种方式“数据库分片”。 1.1 读写分离架构 读写分离原理&#xff1a;将数据库读写操作分散到不同的节点上。 读写分离的基本实现&#xff1a; 主库负责处理事务性的增删改操作&#xff0c…

C++11 右值引用(Rvalue Reference)

在 C++11 中,右值引用(Rvalue Reference) 是一个革命性的语言特性,它为现代 C++ 的性能优化、资源管理以及语义清晰化奠定了基础。通过引入 T&& 语法,C++11 支持了 移动语义(Move Semantics) 和 完美转发(Perfect Forwarding),极大地提升了程序效率和代码表达…

skynet源码学习-skynet_main入口

skynet源码学习-skynet_main入口 核心功能与启动流程Shell脚本启动示例main函数参数处理其他相关联函数解析1. 配置加载器解析2. 环境变量设置3. 配置解析函数 核心配置项解析典型配置文件分析服务启动与运行核心服务启动流程完整启动时序图 核心功能与启动流程 Skynet 的启动…

前端图文混排页面一键导出PDF最佳实践 —— 以Vue3+html2pdf.js为例

前言 在现代管理系统中,数据的归档、分享和线下流转需求日益增长。如何将前端页面的图文内容高质量导出为PDF,成为许多企业和开发者关注的技术点。本文以实际项目为例,系统梳理前端导出PDF的完整实现思路与优化经验。 一、项目背景与需求分析 1.1 背景故事 在某管理系统的…

19|Whisper+ChatGPT:请AI代你听播客

今天&#xff0c;我们的课程开始进入一个新的主题了&#xff0c;那就是语音识别。过去几周我们介绍的ChatGPT虽然很强大&#xff0c;但是只能接受文本的输入。而在现实生活中&#xff0c;很多时候我们并不方便停下来打字。很多内容比如像播客也没有文字版&#xff0c;所以这个时…

linux常用设置

1&#xff0c;ubuntu设置ssh-agent进入shell时自动加载 一&#xff0c;添加自动加载脚本&#xff0c;vim /etc/profile.d/keychain.sh # /etc/profile.d/keychain.sh # 自动启动 ssh-agent 并加载多个私钥 export KEYCHAIN_HOME"/root/.keychain" # 多个key&#xf…

电子电气架构 --- 软件供应商如何进入OEM体系

我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 简单,单纯,喜欢独处,独来独往,不易合同频过着接地气的生活,除了生存温饱问题之外,没有什么过多的欲望,表面看起来很高冷,内心热情,如果你身…

破解数据可视化难题:带轴断裂的柱状图绘制全指南

引言&#xff1a;当数据跨度让图表失真时&#xff0c;轴断裂技术如何力挽狂澜&#xff1f; 在数据可视化的世界里&#xff0c;我们常常会遇到这样的困境&#xff1a;一组数据中既有 "巨无霸" 般的极端值&#xff0c;又有需要精细展示的小数据。比如在财务报表中&…

以太网基础①以太网相关通信接口

1. 今日摸鱼任务 需要学习使用ZYNQ的以太网传输SCPI指令 需要把PL PS两侧的都用起来&#xff08;加油鸭&#xff01;&#xff09; 呐呐呐 今天就先学一下基础知识呗 02_【逻辑教程】基于HDL的FPGA逻辑设计与验证教程V3.5.2.pdf 51 以太网相关通信接口详解 52 以太网&#xff…

FPGA基础 -- Verilog 共享任务(task)和函数(function)

Verilog 中共享任务&#xff08;task&#xff09;和函数&#xff08;function&#xff09; 的详细专业培训&#xff0c;适合具有一定 RTL 编程经验的工程师深入掌握。 一、任务&#xff08;task&#xff09;与函数&#xff08;function&#xff09;的基本区别 特性taskfunctio…

学习大模型---需要掌握的数学知识

1. 线性代数&#xff1a;乐高积木的世界 想象你有很多乐高积木块。线性代数就是研究怎么用这些积木块搭建东西&#xff0c;以及这些搭建好的东西有什么特性的学问。 向量&#xff1a; 就像一个有方向的箭头&#xff0c;或者一组排好队的数字。比如&#xff1a; 一个箭头&…

明远智睿RK3506开发板:多核异构架构赋能高可靠性工业与商业应用

在工业4.0与物联网&#xff08;IoT&#xff09;技术快速发展的背景下&#xff0c;嵌入式系统对性能、功耗、可靠性和实时性的要求日益严苛。针对这一趋势&#xff0c;瑞芯微推出的RK3506开发板凭借其创新的三核A7单核M0多核异构架构、高能低耗设计以及丰富的外设资源&#xff0…

【AI时代速通QT】第二节:Qt SDK 的目录介绍和第一个Qt Creator项目

目录 一、认识 Qt SDK 的目录结构 二、第一个 Qt 程序 2.1 Qt Creator 创建项目 2.2 介绍项目各文件 三、揭秘 Qt 的构建过程 四、运行项目与总结 &#x1f3ac; 攻城狮7号&#xff1a;个人主页 &#x1f525; 个人专栏:CQT跨平台界面编程 ⛺️ 君子慎独! &#x1f308…