最近在做优化的时候涉及到了这块内容,觉得值得写下来,方便以后翻阅。
大家好,我是Halcyon.平安
欢迎文末添加好友交流,共同进步!
- 一、绝对路径为什么不科学
二、相对路径:更好一点,但仍不完美 三、QRC 机制:从根本上解决坑 四、QRC 的标准化操作步骤 五、揭开 QRC 的奥秘:qrc_resource.cpp 六、QRC 机制核心总结七、回顾:三种资源加载方案对比上一篇我们用 setWindowIcon 给窗口设置了图标,但当时用的是绝对路径 E:/baba.png 来加载图片。这种写法科学吗?程序发布到用户电脑上还能正常显示图标吗?本章节我们就来好好聊一聊文件路径的处理方案,以及 Qt 提供的终极解法——QRC 资源机制。
一、绝对路径为什么不科学
刚才我们是这样写的:
QIcon icon("E:/baba.png");
直接把图片放在 E盘下面,然后去查找 E盘的 baba.png 来完成加载。那么坑来了——
如果这个图片不存在,会怎么样?
例如说假设我现在把这个文件名改了,或者把这个图片移到其他地方了,但是代码没有发生改变。再次运行程序——
此时我们会发现,这里并不会报错,但是图标仍然是之前那个默认的图标。
1.1 各位不能假设用户的电脑和你一样
这种绝对路径的方式并不科学,主要原因就是——
你写的程序,最终是要发布到用户的电脑上的。此时你无法确保你开发机上图片的路径,和用户电脑上图片的路径完全一致。
就例如刚才我把图放在 D 盘了,有没有可能那个用户他的电脑上就没有 D 盘,只有一个 C 盘呢?
所以如果你在代码里把路径写死成什么 D 盘的什么路径——
- 万一人家电脑上没这个路径,那就麻烦了
- 就算有这个路径,你能确保人家用户不小心就把这个图片给搞没了吗?这都不好说呀
二、相对路径:更好一点,但仍不完美
相比于绝对路径,相对路径会更好一些。
2.1 什么是相对路径
所谓的相对路径,其实同学们应该也不陌生。它就是——
以给定的一个目录作为基准,往往是以 . 或 .. 的方式开头,通过这个基准来找到目标。
其中:
.表示当前目录(即基准目录)..表示当前路径的上级路径
2.2 几个例子
假设基准目录是 D:/:
相对路径写法含义./baba.png在基准目录 D:/ 下直接找 baba.png./image/baba.png在基准目录中先找 image 目录,再在里面找 baba.png../baba.png往上一级目录找 baba.png
2.3 相对路径的优势
用相对路径的好处就是——可以避免开发机上的路径和目标用户机器路径不一致的坑。
你无法确保用户电脑上有没有 D 盘、E 盘,但只要把图片和可执行程序放在一个相对合适的位置中,不管用户实际那个绝对路径是什么,程序都可以正常运行。
2.4 相对路径的局限
但是即使如此,相对路径这种方式,也没法确保这个文件不被用户搞丢。
就算你写相对路径,你也得把图片和你的 EXE 程序一起,按照相对路径的目录结构打包发给用户。那万一用户不小心就把那个图片整没了,这个事情还是一个比较麻烦的事情。
三、QRC 机制:从根本上解决问题
那怎么样才能够更好地解决上述问题呢?其实在 Qt 里面,还提供了另外一个更好的机制——QRC 机制。
这个机制就是从根本上解决上述两个问题:
确保图片所在的路径在目标用户机器上存在确保图片不会被用户搞丢
3.1 它是怎么做到的
这个事情其实也比较简单,不过还挺神奇的。怎么搞呢?
第一步:我们会给这个 Qt 项目引入一个额外的 XML 文件。说是 XML 文件,但后缀名我们用 .qrc 来表示。
第二步:我们就会在这个 XML 中,把你要用的图片资源给它导入进来,并在这个 XML 中记录下这个图片所在的位置等信息。
第三步(关键):后续 Qt 在编译的时候,就会根据 .qrc 中所描述的图片信息,找到图片内容,提取出图片的二进制数据,最终把这些二进制数据转成 C++ 代码,编译到 EXE 里。
所以通过这样的机制,一通倒腾之后,好了——这回你这个图片它变成了 EXE 的一部分,你总不至于说把 EXE 整没了吧? 你 EXE 都没了,那程序咋运行啊?它肯定运行不了,所以用户手里头必然会有这个 EXE。
图片已经是 EXE 里面的一部分了,所以就不存在说用户把图片搞没了、或者路径搞错了——这些幺蛾子统统没有了。
3.2 QRC 的优缺点
优点缺点路径无关,不怕用户机器路径不一致无法导入太大的资源文件资源不会被用户误删大资源会大幅拉长编译时间加载稳定,怎么着都能正确显示增大 EXE 体积拖慢程序加载运行速度
你要是搞几个图片啥的,其实都还好。但如果你搞个什么几个 GB 的视频文件——那 QRC 就无能为力了。
一方面,编译消耗的时间会非常大,因为它需要把这几个 GB 转换成 C++ 代码;另一方面最终编译成的 EXE 也会非常大,后续操作系统去加载这个 EXE 也会非常慢。所以这种操作就不合适了。
适用边界:
- ✅ 图片、字体、小体积音频这种单文件 MB 级以内的资源
- ❌ GB 级的音视频、动画等大体积资源
3.3 不是 Qt 独有的
而且这种机制也并非是 Qt 独自发明的,很多图形化界面框架都提供了类似的机制。
例如像安卓里头也有类似机制,也是把这些资源文件给它进行了一个编译打包。综上这种把小体积资源嵌入可执行文件的方式,是各类框架通用的设计思路。
四、QRC 的标准化操作步骤
接下来我们就演示一下 QRC 的使用方式。用法其实也比较简单,老师给大家操作一遍,大家一看基本也就了解个七七八八了。
不成文的规矩:创建 QRC 文件时,文件名不要带中文和特殊符号。这不仅是 Qt,很多地方都是这个样子——路径里头不要带中文、不要带特殊符号,属于一个潜规则。后面我们可能就不会再特意强调了,大家记得有这么一回事。
【实操】创建并使用 QRC 资源文件
目标:把 baba.png 通过 QRC 机制打包进 EXE,用 :/baba.png 的方式加载图标。
第一步:创建 QRC 文件
操作:
1. 在 Qt Creator 中点击 文件 → 新建文件
2. 注意——我们创建的不是项目,而是文件
3. 左侧分类选择 Qt,右侧选择 Qt Resource File(别选错了!)
4. 文件名命名为 resource.qrc(名称随便起,但不要带中文和特殊符号)
5. 下一步,是否加入版本控制——无所谓,按需选择,点完成
第二步:添加虚拟前缀(Prefix)
点击完成后,Qt Creator 会打开一个资源文件的可视化编辑器。
操作:
1. 点击 Add Prefix 按钮
2. 它会自动生成一个前缀名,类似 /new/prefix1——这些我们都不要
3. 直接把前缀名改成 / 即可
前缀是什么?
前缀你可以搞懂成一个虚拟的目录,这个目录并没有在你的电脑上真实存在,是 Qt 自己抽象出来的。
因为 QRC 机制本质上是把图片的二进制数据转成了 C++ 代码,最终我们在代码中还得通过"路径"去访问它。为了方便访问,Qt 就抽象出了这样的虚拟目录。
我们就把图片导入到这个虚拟目录下,后面通过"前缀 + 文件名"的方式就能访问到。
第三步:导入图片资源
操作:
1. 先创建好前缀,Add Files 按钮才会从灰色变成可用
2. 点击 Add Files,弹出文件选择对话框
3. 关键限制:导入的图片一定要放在 resource.qrc 文件的同级目录,或者同级目录下的子目录中
易错点:如果你直接去 D 盘选 baba.png,会报"无效"错误!因为 QRC 要求资源文件一定要和 .qrc 文件同级,或在同级子目录下。
解决办法:把 baba.png 拷贝到当前项目目录中(即 resource.qrc 所在目录),然后再 Add Files 选择它。
1. 选中项目目录下的 baba.png,确定
2. 弹出"是否添加版本控制",点 Yes
3. 导入成功后,上方会显示一个带缩略图的树状图,能见到 baba.png 就说明导入成功了
第四步:在代码中通过 : 前缀访问资源
代码参考:
#include "widget.h"
#include "ui_widget.h"
#include // QIcon 头文件
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
// 把原来的绝对路径注释掉
// QIcon icon("E:/baba.png");
// 改用 QRC 资源路径访问
// 规则:冒号前缀 + 虚拟前缀 + 文件名
// 我们创建的前缀是 "/",文件名是 "baba.png"
// 所以路径写作 ":/baba.png"
QIcon icon(":/baba.png");
this->setWindowIcon(icon);
}
访问规则(重要):
当代码中需要访问 QRC 中管理的文件时,路径一定要以冒号 : 作为前缀。Qt 见到这个前缀,就知道——“这个东西要去 QRC 里面查找”。
冒号后面拼接的就是:
你创建的前缀名(这里是 /)加上文件名(这里是 baba.png)
所以最终路径就是 :/baba.png。
前缀叫啥名字,代码里就写啥名字;文件名叫啥,代码里就写啥。
第五步:运行验证
验证流程:
1. 运行程序,观察窗口左上角和任务栏——图标应该正常显示为你设置的 baba.png
2. 此时即使把项目目录下的 baba.png 文件删掉,程序依然能正常显示图标!因为图片数据已经被编译进 EXE 了
五、揭开 QRC 的奥秘:qrc_resource.cpp
为了让大家彻底搞懂这个机制,我们打开项目生成的构建目录看一看里面的奥秘。
5.1 找到构建目录
操作:
1. 关闭运行中的程序
2. 在 Qt Creator 中右键 .pro 文件 → 在 Explorer 中打开
3. 往上一级目录走,找到构建目录(通常在 build-xxx-Debug 之类的目录下)
4. 进入 debug 子目录
5.2 看一下里面有什么
在这个目录下,你会发现:
- ❌ 没有
baba.png——构建目录里并不包含原始的图片文件 - ✅ 多了一个文件:
qrc_resource.cpp
这就是主角! 咱们 QRC 中导入的图片资源,就会被转成这个 qrc_resource.cpp 的 C++ 代码。
5.3 打开看看里面长啥样
把这个文件直接拖到 Qt Creator 里打开,会发现——
- 文件内容还挺大的,看起来都是一些二进制的数据
- 里面有一个数组,叫做
qresourceData之类的名字 - 这个数组是一个
unsigned char数组——里面每一个元素都是一个字节
我们相当于把刚才导入的这一张图片,它里面的二进制数据,就按照这种字节的方式写到这个数组里面了。所以这里的字节内容,就是我们那个 baba.png 里的每个字节的数据。
你甭管是图片也好,音频也好,视频也好,它终究都是由二进制数据构成的——这就是整个计算机的基本盘。所以这个二进制你可以直接放在文件中表示,当然也可以放在一个数组中表示。
5.4 编译时发生了什么
很明显,当我们 Qt 项目进行编译的时候,这个 qrc_resource.cpp 文件就被一起编译到了 EXE 中。
这个时候就相当于说——我们的图片已经融合成 EXE 里面的一部分了,这个时候就再也不怕弄丢了。
另一方面,当我们的 EXE 程序运行的时候,上述图片的数据也就被加载到内存中了——别忘了,数组就是一个变量嘛,变量肯定在内存里。所以我们在程序中随时能找到这段内存数据,也随时能把图片内容获取到。
注意:这个 qrc_resource.cpp 不是我们自己写的,是 Qt 自动生成的,不要手动去改它。
六、QRC 机制核心总结
维度说明机制本质通过 XML 格式的 .qrc 文件记录资源路径,编译时把资源二进制转成 C++ 数组编入 EXE核心优势路径无关、资源不丢失、加载稳定适用场景图片、字体、小体积音频(单文件 MB 级以内)禁用场景GB 级音视频、动画等大体积资源访问方式: 前缀 + 虚拟前缀 + 文件名,例如 :/baba.png生成产物qrc_resource.cpp(Qt 自动生成,含 unsigned char 数组)
通过这种方式,我们就见到了 Qt 针对资源文件的核心处理方式。最大的优势就是路径无关、不怕图片搞没——确保资源发布到用户主机上时不会丢,怎么着都能正确显示。
但另一方面,你也不能搞太大的资源——图片、字体这种小资源没问题,但格外大的音频、视频、动画,产生的数组也会很大,会直接对编译速度和后续的程序加载运行速度产生明显影响,所以要慎重使用。
七、回顾:三种资源加载方案对比
最后我们用一张表把三种方案对比一下,作为本系列资源管理部分的收尾:
方案路径写法路径一致性资源丢失风险适用场景绝对路径"E:/baba.png"❌ 无法保证❌ 高几乎不建议用相对路径"./image/baba.png"✅ 可保证❌ 仍存在资源较大、不宜内嵌时QRC 机制":/baba.png"✅ 完全无关✅ 不会丢小体积资源(建议用)
这次我们详细讲解了 QRC 文件——如何使用、如何导入资源、如何访问。后续我们再用到这块东西的时候,就不再详细讲了,直接拿过来咔咔就开始使用了,所以希望同学们能够掌握这个操作过程。
以上就是这次整理的全部内容,希望对你有所启发。如果有不同见解,欢迎在评论区交流讨论。
评论 (0)
暂无评论