You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

在Visual Studio 2022 C++项目中嵌入资源文件并实现程序内部读取的方法咨询

在Visual Studio 2022 C++项目中嵌入资源文件并实现程序内部读取的方法咨询

嘿,这个需求我之前也碰到过,在Visual Studio 2022里把数据文件嵌入到C++程序里做成单文件可执行档完全没问题,我给你一步步讲怎么操作:

第一步:把data.dat添加为项目资源

  • 右键点击你的C++项目名称,选择「添加」→「资源」;
  • 在弹出的「添加资源」窗口里,点击右下角的「导入」按钮,找到你本地的data.dat文件;
  • 导入时会弹出「自定义资源类型」的对话框,你可以输入一个自定义类型名(比如MY_DATA,建议大写),也可以直接用默认的RCDATA类型,点击确定就完成导入了。

第二步:确认资源脚本配置

导入后,你的项目里会自动生成一个.rc资源脚本文件,打开它能看到类似这样的条目:

MY_DATA DATA "C:/MyData/data.dat"

这里的MY_DATA是你的资源标识名,DATA是资源类型,后面是文件的原始路径。如果觉得绝对路径麻烦,你可以把data.dat复制到项目根目录下,改成相对路径(比如"data.dat"),这样团队协作或者换电脑时更方便。

第三步:修改C++代码,从资源中读取数据

接下来你要把原来代码里的"C:/MyData/data.dat"路径替换成资源读取逻辑,具体代码如下:

首先引入必要的头文件:

#include <windows.h>
#include <vector>
#include <sstream>
#include <fstream>

然后写一个加载资源的工具函数:

// 加载嵌入的资源数据,返回字节数组
std::vector<char> LoadEmbeddedData() {
    // 获取当前exe的模块句柄
    HMODULE hModule = GetModuleHandle(nullptr);
    // 查找资源,第一个参数是资源名,第二个是资源类型,要和rc文件里的对应
    HRSRC hResource = FindResource(hModule, L"MY_DATA", L"DATA");
    if (!hResource) {
        // 处理资源找不到的错误,比如打印日志或者返回空数组
        return {};
    }

    // 加载资源到内存
    HGLOBAL hGlobal = LoadResource(hModule, hResource);
    if (!hGlobal) {
        return {};
    }

    // 获取资源大小和数据指针
    DWORD dataSize = SizeofResource(hModule, hResource);
    const char* pData = static_cast<const char*>(LockResource(hGlobal));

    // 把数据复制到vector里,方便后续使用
    std::vector<char> resourceData(pData, pData + dataSize);
    
    // 解锁资源(可选,进程结束后系统会自动释放)
    UnlockResource(hGlobal);

    return resourceData;
}

最后在业务代码里替换原来的文件读取逻辑:

// 原来的代码可能是这样:
// std::ifstream file("C:/MyData/data.dat", std::ios::binary);
// ...

// 现在改成从资源加载
std::vector<char> embeddedData = LoadEmbeddedData();
if (!embeddedData.empty()) {
    // 如果你的代码需要用文件流来读取,可以把数据转成字符串流
    std::istringstream dataStream(std::string(embeddedData.begin(), embeddedData.end()));
    // 接下来就像操作普通文件流一样使用dataStream即可
    // 比如读取整数、字符串等:
    int value;
    dataStream >> value;

    // 要是某些库必须要求文件路径,也可以把资源数据写入临时文件
    std::string tempFilePath = std::tmpnam(nullptr);
    std::ofstream tempFile(tempFilePath, std::ios::binary);
    tempFile.write(embeddedData.data(), embeddedData.size());
    tempFile.close();
    // 这里就可以用tempFilePath作为文件路径传入库函数
    // 使用完成后记得删除临时文件
    std::remove(tempFilePath.c_str());
}

一些注意事项

  • 如果你用的是默认的RCDATA类型,FindResource的第二个参数可以用MAKEINTRESOURCE(IDR_RCDATA1)这样的宏(具体ID看你导入资源时自动生成的编号);
  • 项目的字符集设置会影响资源名的写法:如果是「Unicode字符集」,要给资源名和类型加L前缀(比如L"MY_DATA");如果是「多字节字符集」,直接写字符串就行;
  • 资源嵌入后,exe的体积会增加,增加的大小就是data.dat的文件大小,这点要留意。

备注:内容来源于stack exchange,提问作者user2138251

火山引擎 最新活动