0

0

c++中如何实现文件的按块读取_c++处理超大文件读取方法【详解】

裘德小鎮的故事

裘德小鎮的故事

发布时间:2026-01-17 15:47:31

|

360人浏览过

|

来源于php中文网

原创

不能直接用std::ifstream::read一次性读完超大文件,因内存不足会导致std::bad_alloc;即使分配成功,缓存失效和页交换也会使性能下降十倍以上。

c++中如何实现文件的按块读取_c++处理超大文件读取方法【详解】

为什么不能直接用 std::ifstream::read 一次性读完超大文件

因为内存不够。比如一个 20GB 的日志文件,new char[20ULL * 1024 * 1024 * 1024] 直接失败,std::bad_alloc 是最常见结果。更隐蔽的问题是:即使系统允许分配(如使用虚拟内存),后续处理时缓存失效、页交换会拖慢十倍以上——这不是 IO 瓶颈,是内存访问模式问题。

按块读取的核心不是“分多次调用 read”,而是控制每次真正加载进物理内存的数据量,并让 OS 缓存策略与你的访问顺序对齐。

用固定大小缓冲区 + read 循环是最稳的方案

不要依赖 gcount() 判断是否读到末尾——它只反映上一次 read 实际读入字节数,而 EOF 可能在任意位置发生。正确做法是检查 rdstate() 并结合 gcount()

  • std::ifstream 必须用 std::ios::binary 模式打开,否则 Windows 下遇到 \r\n 会被静默转换,块边界错乱
  • 缓冲区大小建议设为 4KB–64KB(如 constexpr size_t BUF_SIZE = 8192;),太小导致 syscall 过多,太大无益于性能提升
  • 每次 read(buf, BUF_SIZE) 后立刻检查:if (file.gcount() == 0 && file.eof()) break;,避免空循环
  • 处理最后一块时,gcount() 返回值就是真实可用字节数,不要硬当成满缓冲区用
constexpr size_t BUF_SIZE = 32768;
std::ifstream file("huge.log", std::ios::binary);
if (!file) return;

char buffer[BUF_SIZE]; while (file.read(buffer, BUF_SIZE) || file.gcount() > 0) { size_t n = static_cast(file.gcount()); process_chunk(buffer, n); // 自定义处理函数 if (file.eof()) break; }

需要更高吞吐?试试 mmap(Linux/macOS)或 CreateFileMapping(Windows)

内存映射不是“把整个文件装进内存”,而是建立虚拟地址映射,按需触发 page fault 加载——这比手动 read/write 更贴近现代 SSD/NVMe 的并行读取能力。但代价是:你得自己管理映射范围、处理信号(如 SIGBUS)、且跨平台封装成本高。

医真AI+开放平台
医真AI+开放平台

医真AI+ 医学AI开放平台

下载

立即学习C++免费学习笔记(深入)”;

  • Linux 下用 mmap(nullptr, len, PROT_READ, MAP_PRIVATE, fd, offset)len 不必等于文件大小,可分段映射
  • Windows 需先 CreateFile 得句柄,再 CreateFileMapping + MapViewOfFile
  • 注意:映射区域不可写时,传 PROT_READPAGE_READONLY;若后续要修改,必须用 MAP_SHAREDPAGE_READWRITE
  • mmap 失败返回 MAP_FAILED(不是 nullptr),别漏判

跳过某段内容?别用 seekg 频繁定位

对机械硬盘或某些网络文件系统,seekg 后紧跟 read 会产生大量寻道延迟。如果目标是“跳过前 100MB 解析后续”,更高效的做法是:用 read 循环丢弃数据,而不是反复 seek —— 因为连续读比随机 seek 快 3~10 倍。

  • 丢弃数据时,复用同一缓冲区(如 8KB),避免堆分配开销
  • 若需精确跳转到某行(如 CSV 第 100 万行),先用 read 找换行符,而不是逐字节 get()
  • seekgstd::ios::binary 模式下是字节偏移,安全;但在文本模式下行为未定义,禁用

超大文件处理真正的复杂点不在“怎么读”,而在“怎么定义‘一块’”:是固定字节数?按行?按 JSON 对象边界?这些语义解析逻辑一旦和底层读取耦合,就很难测试和复用。宁愿多一层抽象,把“块提取”和“块处理”拆开。

相关专题

更多
json数据格式
json数据格式

JSON是一种轻量级的数据交换格式。本专题为大家带来json数据格式相关文章,帮助大家解决问题。

412

2023.08.07

json是什么
json是什么

JSON是一种轻量级的数据交换格式,具有简洁、易读、跨平台和语言的特点,JSON数据是通过键值对的方式进行组织,其中键是字符串,值可以是字符串、数值、布尔值、数组、对象或者null,在Web开发、数据交换和配置文件等方面得到广泛应用。本专题为大家提供json相关的文章、下载、课程内容,供大家免费下载体验。

533

2023.08.23

jquery怎么操作json
jquery怎么操作json

操作的方法有:1、“$.parseJSON(jsonString)”2、“$.getJSON(url, data, success)”;3、“$.each(obj, callback)”;4、“$.ajax()”。更多jquery怎么操作json的详细内容,可以访问本专题下面的文章。

309

2023.10.13

go语言处理json数据方法
go语言处理json数据方法

本专题整合了go语言中处理json数据方法,阅读专题下面的文章了解更多详细内容。

74

2025.09.10

if什么意思
if什么意思

if的意思是“如果”的条件。它是一个用于引导条件语句的关键词,用于根据特定条件的真假情况来执行不同的代码块。本专题提供if什么意思的相关文章,供大家免费阅读。

743

2023.08.22

java中break的作用
java中break的作用

本专题整合了java中break的用法教程,阅读专题下面的文章了解更多详细内容。

118

2025.10.15

java break和continue
java break和continue

本专题整合了java break和continue的区别相关内容,阅读专题下面的文章了解更多详细内容。

256

2025.10.24

堆和栈的区别
堆和栈的区别

堆和栈的区别:1、内存分配方式不同;2、大小不同;3、数据访问方式不同;4、数据的生命周期。本专题为大家提供堆和栈的区别的相关的文章、下载、课程内容,供大家免费下载体验。

389

2023.07.18

高德地图升级方法汇总
高德地图升级方法汇总

本专题整合了高德地图升级相关教程,阅读专题下面的文章了解更多详细内容。

27

2026.01.16

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
PostgreSQL 教程
PostgreSQL 教程

共48课时 | 7.3万人学习

Git 教程
Git 教程

共21课时 | 2.7万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号