You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将文件打包进可执行程序并在运行时访问?

二进制文件嵌入可执行程序的完整方案

这种将资源嵌入可执行文件的做法非常普遍,比如嵌入式程序、轻量桌面工具、游戏小资源包等都会采用,避免部署时的文件依赖问题。以下分平台给出完整的构建+运行时方案,均兼容C++11及更早版本:


一、GNU/Linux + ELF 环境(重点)

构建阶段:用objcopy生成可链接目标文件

借助GNU binutils工具链的objcopy,直接将二进制文件转换为ELF目标文件,可直接参与链接:

  1. 将foo.bin转换为foo.o:
# 64位系统
objcopy --input binary --output elf64-x86-64 --binary-architecture i386:x86-64 foo.bin foo.o
# 32位系统替换为
# objcopy --input binary --output elf32-i386 --binary-architecture i386 foo.bin foo.o

该命令会自动生成三个全局符号:

  • _binary_foo_bin_start:嵌入数据的起始地址
  • _binary_foo_bin_end:嵌入数据的结束地址
  • _binary_foo_bin_size:嵌入数据的字节大小
  1. 编译时将foo.o与源码一起链接:
g++ main.cpp foo.o -o my_program

运行时访问数据

在C代码中声明外部符号(用extern "C"避免C名字修饰):

#include <cstddef>
// C++03替换为unsigned char,C++11可用std::byte
typedef unsigned byte;

extern "C" {
    extern const byte _binary_foo_bin_start[];
    extern const byte _binary_foo_bin_end[];
    extern const size_t _binary_foo_bin_size;
}

int main() {
    const byte* data_ptr = _binary_foo_bin_start;
    size_t data_size = _binary_foo_bin_size;

    // 示例:遍历数据
    for (size_t i = 0; i < data_size; ++i) {
        // 处理data_ptr[i]
    }
    return 0;
}

可选:从可执行文件提取数据

用objcopy反向导出:

objcopy --only-section .data my_program extracted_foo.bin

二、Windows 环境

构建阶段:用资源脚本嵌入

Windows可执行文件原生支持资源段,通过资源脚本实现嵌入:

  1. 创建foo.rc资源脚本:
FOO_BIN RCDATA "foo.bin"

其中FOO_BIN是自定义资源ID,RCDATA表示原始数据类型。

  1. 编译资源脚本为.res文件:
rc /v foo.rc

(Visual Studio项目中直接添加.rc文件即可,IDE会自动处理编译)

  1. 链接时将.res与源码结合:
cl main.cpp foo.res /Fe:my_program.exe

运行时访问数据

通过Windows API读取资源:

#include <windows.h>
#include <cstddef>

int main() {
    HMODULE hModule = GetModuleHandle(NULL);
    // 查找资源
    HRSRC hRes = FindResource(hModule, MAKEINTRESOURCE(FOO_BIN), RT_RCDATA);
    if (!hRes) { /* 错误处理 */ }

    // 加载资源
    HGLOBAL hResData = LoadResource(hModule, hRes);
    if (!hResData) { /* 错误处理 */ }

    // 锁定资源获取数据指针
    const unsigned char* data_ptr = static_cast<const unsigned char*>(LockResource(hResData));
    size_t data_size = SizeofResource(hModule, hRes);

    // 使用数据
    return 0;
}

可选:从可执行文件提取数据

用Resource Hacker工具打开exe,找到RCDATA类型的FOO_BIN资源,直接导出即可。


三、macOS 环境

构建阶段:用ld的-sectcreate选项

针对Mach-O格式,通过链接器选项直接创建自定义节嵌入数据:

  1. 编译源码为目标文件:
clang++ -c main.cpp -o main.o
  1. 链接时嵌入foo.bin:
clang++ main.o -o my_program -sectcreate __DATA __foo_bin foo.bin

其中__DATA是段名,__foo_bin是节名,可自定义。

运行时访问数据

用getsectdata函数获取节数据:

#include <mach-o/getsect.h>
#include <cstddef>

int main() {
    size_t data_size;
    const unsigned char* data_ptr = static_cast<const unsigned char*>(
        getsectdata("__DATA", "__foo_bin", &data_size)
    );
    if (!data_ptr) { /* 错误处理 */ }

    // 使用数据
    return 0;
}

可选:从可执行文件提取数据

先用otool查看节的偏移和大小:

otool -l my_program | grep -A 10 __foo_bin

再用dd提取(替换示例中的偏移和大小):

dd if=my_program of=extracted_foo.bin skip=$((0x1234)) count=$((0x5678)) bs=1

通用注意事项

  • 嵌入的数据默认处于只读段,安全性更高;若需可写,需调整工具参数(不推荐)。
  • 大文件嵌入会显著增加可执行文件体积,需权衡资源大小与部署便利性。
  • 跨平台场景可通过CMake等构建系统封装上述步骤,自动适配不同平台的嵌入逻辑。

内容的提问来源于stack exchange,提问作者einpoklum

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.02 06:54:52