0

0

c++中如何实现简单的文件分块读取_c++大文件处理技巧【实例】

尼克

尼克

发布时间:2026-01-16 17:39:37

|

745人浏览过

|

来源于php中文网

原创

不能直接用fread一次性读完大文件,因32位程序无法分配4GB单块缓冲区,64位下也易阻塞线程、触发OOM,且多数场景无需全量驻留内存;应分块读取并正确处理边界与EOF。

c++中如何实现简单的文件分块读取_c++大文件处理技巧【实例】

为什么不能直接用 fread 一次性读完大文件

内存不够是硬限制。比如一个 4GB 的日志文件,在 32 位程序里根本无法分配单块 4GB 缓冲区;即使在 64 位下,一次性加载也会阻塞主线程、拖慢响应,还可能触发系统 OOM Killer。更关键的是,多数场景(如校验、过滤、流式解析)根本不需要全量驻留内存。

fseek + fread 分块读取的可靠写法

核心是控制每次读取的字节数,并正确处理边界和 EOF。注意:不能依赖 fread 返回值等于请求长度来判断是否读完——最后一块通常不足。

  • fseek(fp, offset, SEEK_SET) 定位到起始位置,offset 必须是 long 类型,超 2GB 文件需确保编译器支持 _FILE_OFFSET_BITS=64(Linux)或使用 _fseeki64(Windows)
  • 每次调用 fread(buf, 1, chunk_size, fp) 后,检查返回值 size_t n = fread(...),它表示**实际读到的字节数**,可能为 0(EOF 或出错)
  • 读完一块后不要立刻 fseek 到下一块——应基于本次 n 计算下一次 offset,避免因换行符、编码边界等导致跳过数据
FILE* fp = fopen("huge.log", "rb");
if (!fp) return;
const size_t chunk_size = 64 * 1024; // 64KB
char* buf = new char[chunk_size];
size_t offset = 0;

while (true) { fseek(fp, offset, SEEK_SET); size_t n = fread(buf, 1, chunk_size, fp); if (n == 0) break; // EOF or error

// 处理 buf[0..n-1]
process_chunk(buf, n);

offset += n; // 下一块从当前位置开始,不跳字节

} delete[] buf; fclose(fp);

std::ifstream 分块时必须避开的坑

std::ifstream 默认启用缓冲,但 read() 在二进制模式下行为与 C 风格一致;问题多出在文本模式(自动换行转换)、异常掩码未关闭、以及 gcount() 被忽略。

  • 务必调用 file.open("...", std::ios::binary),否则 Windows 下 \r\n 可能被误转为 \n,破坏原始字节偏移
  • 不要用 file >>getline() 处理大文件——它们内部会反复调用 sbumpc(),性能极差且无法控制块大小
  • 每次 read(buf, size) 后,必须用 file.gcount() 获取真实读取字节数,file.fail()file.eof() 需配合判断:仅当 gcount() == 0 && !fail() 才是干净 EOF

分块大小选 64KB 还是 1MB?看 I/O 模式和设备

不是越大越好。机械硬盘随机读取 1MB 块可能比顺序读慢 20%,而 SSD 上差异不大;但内存拷贝开销、cache line 对齐、以及下游处理单元(如解压、加密)的吞吐瓶颈更关键。

Smart Picture
Smart Picture

Smart Picture 智能高效的图片处理工具

下载

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

  • 纯顺序扫描(如统计行数):64KB ~ 256KB 平衡了系统调用开销和 cache 效率
  • 需要按固定结构解析(如 protobuf record):块尾需预留至少一个完整 record 长度,避免跨块截断,此时建议 1MB + 边界对齐逻辑
  • 网络文件系统(NFS/SMB):小块(8KB~32KB)更稳定,大块易触发 timeout 或重传

真正难的不是怎么读,而是怎么定义“块”——是按字节切分,还是按逻辑记录切分;后者要求预读+回退机制,容易漏掉跨块的换行或帧头。

相关专题

更多
fclose函数的用法
fclose函数的用法

fclose是一个C语言和C++中的标准库函数,用于关闭一个已经打开的文件,是文件操作中非常重要的一个函数,用于将文件流与底层文件系统分离,释放相关的资源。更多关于fclose函数的相关问题,详情请看本专题下面的文章。php中文网欢迎大家前来学习。

326

2023.11.30

线程和进程的区别
线程和进程的区别

线程和进程的区别:线程是进程的一部分,用于实现并发和并行操作,而线程共享进程的资源,通信更方便快捷,切换开销较小。本专题为大家提供线程和进程区别相关的各种文章、以及下载和课程。

480

2023.08.10

线程和进程的区别
线程和进程的区别

线程和进程的区别:线程是进程的一部分,用于实现并发和并行操作,而线程共享进程的资源,通信更方便快捷,切换开销较小。本专题为大家提供线程和进程区别相关的各种文章、以及下载和课程。

480

2023.08.10

数据库Delete用法
数据库Delete用法

数据库Delete用法:1、删除单条记录;2、删除多条记录;3、删除所有记录;4、删除特定条件的记录。更多关于数据库Delete的内容,大家可以访问下面的文章。

269

2023.11.13

drop和delete的区别
drop和delete的区别

drop和delete的区别:1、功能与用途;2、操作对象;3、可逆性;4、空间释放;5、执行速度与效率;6、与其他命令的交互;7、影响的持久性;8、语法和执行;9、触发器与约束;10、事务处理。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

209

2023.12.29

windows查看端口占用情况
windows查看端口占用情况

Windows端口可以认为是计算机与外界通讯交流的出入口。逻辑意义上的端口一般是指TCP/IP协议中的端口,端口号的范围从0到65535,比如用于浏览网页服务的80端口,用于FTP服务的21端口等等。怎么查看windows端口占用情况呢?php中文网给大家带来了相关的教程以及文章,欢迎大家前来阅读学习。

576

2023.07.26

查看端口占用情况windows
查看端口占用情况windows

端口占用是指与端口关联的软件占用端口而使得其他应用程序无法使用这些端口,端口占用问题是计算机系统编程领域的一个常见问题,端口占用的根本原因可能是操作系统的一些错误,服务器也可能会出现端口占用问题。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

1101

2023.07.27

windows照片无法显示
windows照片无法显示

当我们尝试打开一张图片时,可能会出现一个错误提示,提示说"Windows照片查看器无法显示此图片,因为计算机上的可用内存不足",本专题为大家提供windows照片无法显示相关的文章,帮助大家解决该问题。

790

2023.08.01

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

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

2

2026.01.16

热门下载

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

精品课程

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

共48课时 | 7.2万人学习

Git 教程
Git 教程

共21课时 | 2.7万人学习

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

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