最近研究了下如何用qt的原生控件来加载和显示大文件(>1G),分享下一些摸索经验。

下文源码:

compilelife/loginsight​github.com

文件的内存映射

在开始qt部分之前,我们先了解一个概念——文件的内存映射。

我们知道一般读文件用到的API是fopen/fread/fclose,或者是open/read/close,这种方式都需要内核帮忙作一次拷贝。

linux中有一个函数叫mmap(windows也有类似功能),可以避免这样的一次拷贝。

请看这幅对比图(图片来源:https://www.jianshu.com/p/eece39beee20):

当我们用fread/read时,都是触发了一个步骤1的read系统调用,然后内核帮忙到磁盘中把请求的文件内容读取到kernnel buffer,然后再copy回用户进程空间。

相比,如果用mmap,一开始内核就把整个文件映射到了用户进程的虚拟内存中;映射过程只是分配了地址空间,并没有拷贝内存,所以速度快。这一段地址空间在代码层面看到的就是一块连续的内存,当代码访问这块内存,如果引发缺页异常,内核就会加载文件内存到buffer。这样就减少了一次内存拷贝。

使用mmap对于大文件的加载和显示有什么好处呢:

  • 读取速度快
  • 可以把整个文件当做代码中一个连续内存区域,直接以const char*访问,即可以透明地认为整个文件已经加载到进程内,且保存为一个字符串(指针)了。对于代码设计而言较方便。

mmap参考资料: https://www.jianshu.com/p/eece39beee20https://zhuanlan.zhihu.com/p/69555454

Qt里显示大文件

在Qt里,QFile::map提供了跨平台的“文件内存映射”支持。所以通过调用QFile::map就可以把文件“加载”为一个const char*字符串使用。

我们知道,在 QPlainTextEdit里,显示文本一般可以用setPlainText。如果直接把map后的内存传递给setPlainText会导致文件的所有内容被读入内存,这显然是不行的。

一般对大文件处理方式是“分页”,也就是一次只加载部分内容。

为了让用户感知不到文件被“分页”了,我们需要处理下,自动加载分页的内容。具体的做法:

  1. 监听滚动事件,自动加载下一个/上一个分页
  2. 隐藏滚动条,用外部滚动条替代;外部滚动条对应整个文件范围,并保持实时同步

思路

在开始实现前,我们最好有一个清晰的思路,可以建个简单的模型:

这里,我们把窗口可视区想象成一个固定高度的滑块,整个滑块可以在整个文件从头滑动到尾部——对应用户从第一行拉动滚动条(右侧灰色箭头)直到最后一行。

为了能减少滚动过程中频繁触发读取文件,可以设置一块预加载区域,比可见区域大。每次可见区域要滑出预加载区的时候,就触发一次预加载区的预读。

在实现上,预加载区域对应的就是setPlainText加载的内容,而可见区域的滚动就直接由QPlainText代为实现了。

于是,要实现大文件的加载和显示,只要: 1. 预读内容,通过setPlainTextQPlainTextEdit 2. 处理QPlainTextEdit的滚动事件,在即将滚出预读区的时候,更新预读区

当然,说起来容易,做起来还是要处理一些琐碎事务的。详见:https://github.com/compilelife/loginsight/blob/master/src/logtextedit.cpp

再谈文件的内存映射

当然,如果只是单纯地去显示一个大文件, 直接用常规的文件读写API也是可行的。map的优势还不够明显。

实际上,map在这个场景里,真正强大的地方是在于把文件当做“已经加载好的连续字符串”。在加载了大文件后,不可避免地需要做查找、定位等逻辑,这时使用map可同时优化效率和代码可读性。

比如,我们要在上面工作的基础上做全文搜索并定位到匹配行。这时QPlainTextfind因为只能搜索预加载内容,无法使用。而基于map,只需要对map后的内存地址,执行strstr按字符串查找,再把查找到的位置前后内容载入可视区即可。

总结

为了基于qt原生控件去高效地显示大文件,我们用了不少奇技淫巧,把QPlainTextEdit伪装成了支持大文件的文本框。也许下一步可以试试看用QPlainTextDocumentLayout实现自定义文本框,作更深入地优化。

fread读取整个文件_qt如何实现大文件的加载和显示相关推荐

  1. 多文件上传,大文件上传3、5个G,那都不是事

    一套大文件上传的教程给大家. https://www.yyjcw.com/html/ke/34.html 重点讲解了多文件上传,大文件上传,分块上传,断点续传,文件秒传,上传失败自动修复再上传等功能, ...

  2. Python组织文件 实践:查找大文件、 用Mb、kb显示文件尺寸 、计算程序运行时间...

    这个小程序很简单原本没有记录下来的必要,但在编写过程中又让我学到了一些新的知识,并且遇到了一些不能解决的问题,然后,然后就很有必要记录一下. 这个程序的关键是获取文件大小,本来用 os.path.ge ...

  3. nginx配置解决vue单页面打包文件大,首次加载慢的问题

    nginx配置解决vue单页面打包文件大,首次加载慢的问题 参考文章: (1)nginx配置解决vue单页面打包文件大,首次加载慢的问题 (2)https://www.cnblogs.com/golo ...

  4. Python组织文件 实践:查找大文件、 用Mb、kb显示文件尺寸 、计算程序运行时间

    这个小程序很简单原本没有记录下来的必要,但在编写过程中又让我学到了一些新的知识,并且遇到了一些不能解决的问题,然后,然后就很有必要记录一下. 这个程序的关键是获取文件大小,本来用 os.path.ge ...

  5. java rmi 文件传输_JAVA-RMI实现大文件传输

    在使用java-rmi的过程中,必然会遇到一个文件上传的问题,由于在rmi中无法传输文件流(比如rmi中的方法参数不能是FileInputStream之类的),那么我们只好选择一种折中的办法,就是先用 ...

  6. 大文件表空间+创建大文件表空间+查询数据库表空间类型信息+查询数据库表空间类型信息...

    1用于解决存储文件大小不够的问题 2与普通表空间不同的地方在于大文件表空间只对应唯一一个数据文件或临时文件,普通表空间可最多1022个数据文件或临时文件 3大文件表空间对应文件可达4G个数据块大小,普 ...

  7. python大文件排序_Python如何实现大文件排序?Python大文件排序的实现方法

    Python如何实现大文件排序?Python大文件排序的实现方法 本文实例讲述了Python实现大文件排序的方法.分享给大家供大家参考.具体实现方法如下: import gzip import os ...

  8. perl linux 遍历文件,Perl/Linux过滤大文件与其他文件的内容

    我正在使用另一个较小文件的内容过滤580 MB文件. File1中(较小的文件)Perl/Linux过滤大文件与其他文件的内容 chr start End 1 123 150 2 245 320 2 ...

  9. Git入门之命令行删除文件及上传大文件至Github(二)

    自2013年开始,作者的代码基本是分享到CSDN下载区,最早设置均是免费的,但随着下载量增加,分数自动增长.为了更好地分享开源代码及相关工具,赶上时代潮流,作者后续会将代码分享至Github和CSDN ...

最新文章

  1. 150页书籍《PyTorch 深度学习快速入门指南》附PDF电子版
  2. sir跟seir模型有啥区别_H3C B5mini拆机,看一下跟B5有啥区别
  3. 临床预测模型开发checklist详解
  4. Elasticsearch2.x Breaking changes
  5. idea工作台输出的日志详解_详解linux下nohup日志输出过大问题解决方案--分批切割...
  6. 微软悄悄发布了 Web 版的 VsCode
  7. 面试经历—广州YY(欢聚时代)
  8. POJ 3690 找星座(2D匹配)(未解答)
  9. Linux系统中的load average
  10. android java 图像显示不出来_Java-Android Studio无法在图像视图中显示图像
  11. java.lang.NoClassDefFoundError: org/junit/runner/manipulation/Filter
  12. Leetcode-9-回文数(简单)
  13. 净空法师:人到这个世间来干什么?做人的意义究竟在哪里?
  14. Mac 破解zip压缩文件密码详解
  15. 苹果或将采用高通屏下指纹方案,5GiPhone基带由三星、高通共同提供
  16. python-onvif实现客户端控制相机云台
  17. [转载]刘峰获“区块链60人”2020赋能中国区块链创新人物奖
  18. 了解一下,Android 10 Build系统
  19. 为啥VUE和React都选择hooks
  20. 什么软件可以给视频加字幕?这些软件值得收藏

热门文章

  1. maven 项目管理和构建工具
  2. vue中的数据单向绑定,判断,循环,函数
  3. 1020 月饼 (25分)
  4. 利用旧手机自建anki服务器,废旧手机变身服务器,打造私人云盘
  5. 「BZOJ2200」[Usaco2011 Jan] 道路和航线 - 最短路+拓扑排序
  6. 《科技之巅2》序——机器智能数据智能:工具之王
  7. linux意想不到题4
  8. InnoDB还是MyISAM?
  9. 《Linux内核》课本读书笔记 第三章
  10. nginx源码分析—模块及其初始化