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

Qt内存映射到文件,解决打开大文件占用内存高的问题

前言

在开发桌面项目中经常会遇到打开大文件进行解析后对数据进行处理,如果文件太大,解析后的数据全部放到内存中会占用大量的内存,如果同时打开多个文件就会导致内存暴增,最终可能就会出现内存占满而程序崩溃。
解决这个问题,一个比较常见的方法就是实用内存映射到文件。

内存映射文件是一种将文件映射到内存中的技术,通过将文件的内容映射到内存中的一块地址空间,可以直接在内存中对文件进行读写操作,而不需要通过传统的文件IO操作,这一过程涉及创建文件句柄、建立内存映射对象、映射文件到进程空间以及解除映射等步骤。这种方式可以大大提高文件的读写效率,并且方便进行随机访问。

C++的开源库Boost中,可以使用boost::iostreams::mapped_file类来实现内存映射文件的读写操作。该类提供了简单易用的接口,可以方便地进行文件的读写操作。

本文主要介绍Qt中的QFile来实现内存映射操作。使用也非常简单,但是过程中有些步骤需要注意。
在这里插入图片描述

正文

QFileDevice中提供了一个函数 map 用于现内存映射操作,函数定义如下:

uchar *QFileDevice::map(qint64 offset, qint64 size, QFileDevice::MemoryMapFlags flags = NoOptions)

在这里插入图片描述
使用map进行内存映射,unmap取消内存映射。

应用场景

示例场景一: 音频文件编辑

举一个实际的应用场景。

音频文件编辑功能,解析音频的pcm数据后,如果将数据全部放到内存中,然后对内存数据进行操作,理论上是没问题的,但是如果打开的文件比较大,几百兆甚至几个G,将解析的数据放到内存中就会导致内存暴增,如果同时要编辑多个大文件音频,对电脑内存无疑是个巨大的挑战。这种情况下,使用内存映射到文件的方式就是一种很好的选择。

首先将音频解析(如使用FFmpeg)出PCM数据,将PCM数据直接存储到本地文件中,然后将内存映射到该文件,通过指针去操作文件内容、如读取数据、更新数据等。

用法其实很简单:

QFile m_file;
uchar *m_dataPtr;m_file.setFileName(fileName);
if(m_file.open(QIODevice::ReadWrite)){m_dataPtr = m_file.map(0,m_file.size());//to do ...
}

注意,通过map映射后,m_file一定要是打开的状态,如果关闭文件,再操作m_dataPtr 指针将会报错。而且打开文件的方式必须是QIODevice::ReadWrite类型,否则使用指针去更新内存数据时会导致崩溃。

如果使用完毕,要取消映射也很简单,通过unmap,然后关闭文件即可。

if(m_dataPtr){m_file.unmap(m_dataPtr);m_dataPtr = nullptr;
}
if(m_file.isOpen()){m_file.close();
}

注意,如果是在一个类中需要多次操作,可以将指针和文件对象定义成类的成员变量,这样就可以只打开一次文件,然后整个类都可以使用一个指针来操作。

另外,在映射的时候是指定了映射范围的,如 m_file.map(0,m_file.size());是指定了整个文件的大小空间,当然也可以选择某个区间进行映射,这个自己决定就好。
需要注意的是,如果文件内容有新增或删除,通过映射的指针就无法完成,需要取消映射然后关闭文件后,通过QFile去写入新的文件内容,然后重新做映射。

示例场景二:拷贝文件

文件拷贝,大家都知道可以使用QFile::copy的方式来实现,但是对于大文件的拷贝,在实测中,使用内存映射后,直接进行内存拷贝的方式速度更快一些。

上代码:

bool fastCopyFile(const QString &sourceFilePath, const QString &destFilePath)
{//先做内存映射,再做内存拷贝,这种方式比直接使用 QFile::copy效率更高QFile sourceFile(sourceFilePath);QFile destFile(destFilePath);if (!sourceFile.open(QIODevice::ReadOnly)) return false;if (!destFile.open(QIODevice::ReadWrite)) { // 需要 ReadWrite 权限用于映射sourceFile.close();return false;}// 预分配目标文件大小qint64 fileSize = sourceFile.size();destFile.resize(fileSize);// 映射源文件uchar *srcMap = sourceFile.map(0, fileSize);if (!srcMap) {sourceFile.close();destFile.close();return false;}// 映射目标文件uchar *destMap = destFile.map(0, fileSize);if (!destMap) {sourceFile.unmap(srcMap);sourceFile.close();destFile.close();return false;}// 直接内存拷贝memcpy(destMap, srcMap, fileSize);// 解除映射并关闭文件sourceFile.unmap(srcMap);destFile.unmap(destMap);sourceFile.close();destFile.close();return true;
}

这里其实就是用了内存映射到文件的功能,直接操作指针,进行内存拷贝。


文章转载自:

http://uBR3pEjo.cLtrx.cn
http://jCc0MV8m.cLtrx.cn
http://QIW9ZkjV.cLtrx.cn
http://Yr2mconc.cLtrx.cn
http://4bjY8N9o.cLtrx.cn
http://MMxZAB7P.cLtrx.cn
http://t8pGBjue.cLtrx.cn
http://u7q948J0.cLtrx.cn
http://1gOtiodk.cLtrx.cn
http://cfGYe8DA.cLtrx.cn
http://LKiCeP75.cLtrx.cn
http://TnsgjOkM.cLtrx.cn
http://gBwZvdev.cLtrx.cn
http://o8osPbUl.cLtrx.cn
http://nK5mS55Z.cLtrx.cn
http://qyCTGb19.cLtrx.cn
http://r0bdGyCs.cLtrx.cn
http://AR7fuKLM.cLtrx.cn
http://akU6TGb2.cLtrx.cn
http://dewpbDOh.cLtrx.cn
http://xDzQ82H4.cLtrx.cn
http://yhheWwMW.cLtrx.cn
http://kVEqw04l.cLtrx.cn
http://xdV0fOiA.cLtrx.cn
http://jB0jQu37.cLtrx.cn
http://I7Rc5pNV.cLtrx.cn
http://2SxS8EDC.cLtrx.cn
http://aXDnwgm4.cLtrx.cn
http://6zmoCujE.cLtrx.cn
http://Aw3hoWgW.cLtrx.cn
http://www.dtcms.com/a/363647.html

相关文章:

  • Qt5 多媒体大纲
  • 基础算法之二分算法 --- 1
  • 基于SpringBoot的校园资料分享平台
  • 力扣242:有效的字母异位词
  • 漏扫工具使用
  • C++的演化历史
  • Windows控制台颜色修改
  • anaconda下载与pycharm解析器配置
  • TypeScript:内置高级类型
  • vue2 跟 vue3 对比总结
  • Java集合遍历的方法有哪些
  • T40N君正/INGENIC专业嵌入式CPU计算能力,集成XBurst2双核处理器(1.2GHz)、RISC-V协处理器和神经网络加速器(2TOPS算力)
  • 在 macOS 下升级 Python 几种常见的方法
  • 【LeetCode数据结构】栈和队列的应用
  • 洛谷P3811 【模板】模意义下的乘法逆元
  • 硬件开发1-51单片机1
  • 嵌入式 - 硬件:51单片机
  • LeetCode算法日记 - Day 29: 重排链表、合并 K 个升序链表
  • HTML第三课:特殊元素
  • CICD实战(3) - 使用Arbess+GitLab+Hadess实现Java项目构建/上传制品库
  • 人工智能之数学基础:分布函数对随机变量的概率分布情况进行刻画
  • PromptHero-最受欢迎的AI提示词网站
  • TIOBE 8月编程语言榜深度解析:Python占比突破26%,Perl成最大黑马
  • 【3D打印】3D打印机首次使用心得
  • Git相关的命令
  • 力扣hot100:缺失的第一个正数(哈希思想)(41)
  • 领导层必看:Curtain e-locker为您轻松管理“文件外发“
  • MySQL 多表查询方法
  • day42-单片机
  • 基于3dtitle模型无法双面渲染问题