内嵌资源(把文件打进 EXE)
[🕒 预计 15 分钟] | 难度:进阶
内嵌资源让你把任意格式的项目文件(图片、文本、JSON、zip、字体、DLL 字节…)在构建期直接打进 EXE, 运行期用「资源_*」命令按逻辑名读取。程序分发时只需要一个 exe,不再需要把素材文件散落在旁边。
功能由内置模块 lingbuilder.resource.embed(「内嵌资源模块」)提供,清单保存在项目模型里, 跨窗口共享:同一个项目的所有窗口读到的都是同一份资源。
NOTE
内嵌资源只在构建期打包:改了源文件必须重新构建,运行期读到的始终是构建时的内容。 构建产物不会把资源解压到磁盘(除非你显式声明 extract 或调用释放命令)。
1. 什么时候用它
| 场景 | 做法 |
|---|---|
| 单文件分发 | 把图标、说明文件、配置 JSON 内嵌进 exe |
| 交给只吃字节集的接口 | 内存DLL_加载(资源_取字节集("dll/mylib.dll"), "mylib.dll") |
| 交给只吃磁盘路径的老库 | 声明 extract: true,或运行期 资源_释放到临时目录(...) |
| 内嵌网页资源 | 用「内嵌站点」机制配 EdgeView/FBro 浏览器控件(两者怎么选见内嵌站点 vs 内嵌资源) |
2. 在设计器里维护清单
- 打开窗口设计器,选中窗口本身(在画布空白处点一下,让右侧显示「窗口属性」)。
- 在属性面板找到 项目 / 内嵌资源(跨窗口共享) 分组。
- 用两个按钮添加条目:
- 选择文件…:本机多选,选完自动复制进项目(默认
<项目源码根>/resources/<原文件名>,重名自动加-2后缀),逻辑名自动回填。 - 选择文件夹…:本机选目录,递归展开成多条,逻辑名保留文件夹内的相对路径(文件夹名作为顶层目录)。
- 选择文件…:本机多选,选完自动复制进项目(默认
- 想引用工作区内已有文件、不想再复制一份时,在「扫描目录」输入框填工作区相对目录(如
assets),点 扫描目录,逻辑名直接取工作区相对路径。 - 表格里可以直接改逻辑名、源文件,勾选/取消启动释放,点右侧垃圾桶删除条目。
TIP
面板会实时做与构建期同一套校验:逻辑名重复、源文件缺扩展名、路径越界等都会在面板底部用中文提示。 没启用「内嵌资源模块」时面板顶部会给出一键启用入口。
3. 清单写法(手改项目 JSON 时)
清单存在项目设计器模型的顶层 embeddedResources(window-designer.json):
json
"embeddedResources": [
{ "name": "assets/说明.txt", "file": "src/resources/说明.txt" },
{ "name": "assets/包.zip", "file": "src/resources/包.zip", "extract": true },
{ "name": "dll/mylib.dll", "file": "dll/x64/mylib.dll" }
]| 字段 | 含义 |
|---|---|
name | 逻辑名:运行期用它读取。大小写与斜杠方向不敏感,可以用中文与子目录 |
file | 工作区内相对源文件路径(必须带扩展名、位于工作区内) |
extract | 为真时程序启动就释放到 %TEMP%\lingbuilder-embedded\<工程ID>\<逻辑名>,供只接受磁盘路径的 API |
4. 八条命令
| 命令 | 签名 | 说明 |
|---|---|---|
资源_取字节集 | 资源_取字节集(逻辑名) → 字节集 | 读成字节集(失败返回空字节集) |
资源_取文本 | 资源_取文本(逻辑名) → 文本型 | 按 UTF-8 解码(源文件须是 UTF-8) |
资源_是否存在 | 资源_是否存在(逻辑名) → 逻辑型 | 清单里有且 EXE 里能取到 |
资源_取大小 | 资源_取大小(逻辑名) → 整数型 | 原始字节数 |
资源_列表 | 资源_列表() → 文本型 | 每行一个逻辑名,便于自检 |
资源_保存到文件 | 资源_保存到文件(逻辑名, 路径) → 文本型 | 覆盖写成真实文件,返回路径 |
资源_释放到临时目录 | 资源_释放到临时目录(逻辑名) → 文本型 | 释放到 %TEMP%\lingbuilder-embedded\<工程ID>\ 并返回路径 |
资源_取错误信息 | 资源_取错误信息() → 文本型 | 最近一次失败的中文原因 |
5. 完整示例
假设清单里已声明 assets/说明.txt、assets/包.zip、dll/mylib.dll:
text
包 我的程序
使用 Win32窗口基础模块
使用 内嵌资源模块
类 主窗口 : 窗口
公开
事件 _主窗口_创建完毕()
局部 文本型 说明 = ""
局部 整数型 包大小 = 0
局部 字节集 包数据 = 字节集_从文本("")
说明 = 资源_取文本("assets/说明.txt")
包大小 = 资源_取大小("assets/包.zip")
包数据 = 资源_取字节集("assets/包.zip")
调试输出(格式化文本("说明={},压缩包={} 字节", 说明, 包大小))
如果 (包大小 = 0)
调试输出(资源_取错误信息())
如果结束
// 交给只接受磁盘路径的库
局部 文本型 路径 = 资源_释放到临时目录("assets/包.zip")
调试输出(路径)
// 内嵌 DLL 直接内存加载,不落盘
局部 长整数型 模块地址 = 内存DLL_加载(资源_取字节集("dll/mylib.dll"), "mylib.dll")
结束
结束
结束类要点:
- 调用的模块命令,项目必须先在 配置项目所使用模块 中启用「内嵌资源模块」和「内存加载DLL模块」。
- 逻辑名写错时不会崩溃:命令返回空值,用
资源_取错误信息()看中文原因。 - 列表自检:
资源_列表()会打印全部逻辑名,构建后不确定打包了什么就先打它。
6. 构建与放置规则
- 资源号从 2301 起按清单顺序分配(图标 101、内嵌站点 2101+、项目 DLL 2201+ 各自独立)。
- 构建时源文件会被复制成 ASCII 归档名(
resources/res-0001.bin)再交给资源编译器, 因此中文路径与中文文件名都能安全内嵌。 - 上限:条目 ≤ 4096 条、单文件 ≤ 256MB;总量超过 256MB 会在构建日志里给出体积告警(不阻断)。
- 路径必须是工作区内相对路径,且不能包含
..、引号或控制字符。
7. 限制与注意事项
- 仅支持 Windows 目标(PE 资源机制);EXE 体积会随资源总量线性增长。
- 内嵌 ≠ 解压:
资源_取字节集读 zip 拿到的是原始字节。要解压请先资源_保存到文件,再用 ZIP 相关模块处理。 - 不要内嵌
.exe/.com等可执行文件;要内嵌可执行代码请用「内存加载 DLL」链路。 extract: true的释放是覆盖写,每次启动都会重写一遍,路径固定为%TEMP%\lingbuilder-embedded\<工程ID>\。- 旧项目的「窗口内嵌文件」(释放到 %TEMP% 的
embeddedFiles,最多 8 个、没有设计器入口)会在打开/构建时 自动迁移成等价的extract: true内嵌资源,构建日志会给出弃用提示,保存项目即写回新格式。
下一步
- 想内嵌 DLL 并直接调用导出函数:调用 C++ DLL
- 想内嵌整个网页站点:窗口设计器 → 内嵌站点,步骤见 EdgeView 浏览器模块;两种内嵌机制的区别与选型见内嵌站点 vs 内嵌资源
- 回到进阶主题索引