C++ 如何将文件嵌入到可执行文件中?

C++ 如何将文件嵌入到可执行文件中?,c++,c,file,binary,executable,C++,C,File,Binary,Executable,我有两个问题,第一个已经解决了 当前问题 如果我嵌入了一个需要库才能加载的文件,例如jpeg图像或mp3音乐,我将需要使用该文件作为库的输入。但是,每个库都是不同的,并且使用一种方式获取文件作为输入,输入可以是文件名或文件*指针(来自libc的文件接口) 我想知道如何访问带有名称的嵌入式文件。如果我创建一个临时文件,效率会很低,还有其他方法吗?我可以将文件名映射到内存吗?我的平台是Windows和Linux 如果show_file(const char*name)是库中的函数,我需要一个字符串来

我有两个问题,第一个已经解决了

当前问题
如果我嵌入了一个需要库才能加载的文件,例如jpeg图像或mp3音乐,我将需要使用该文件作为库的输入。但是,每个库都是不同的,并且使用一种方式获取文件作为输入,输入可以是文件名或文件*指针(来自libc的文件接口)

我想知道如何访问带有名称的嵌入式文件。如果我创建一个临时文件,效率会很低,还有其他方法吗?我可以将文件名映射到内存吗?我的平台是Windows和Linux

如果show_file(const char*name)是库中的函数,我需要一个字符串来打开该文件。
我看到了这些问题:

下面的代码是我的解决方案。这是一个好的解决方案吗?效率低吗

# include <stdio.h>
# include <unistd.h>

extern char _binary_data_txt_start;
extern const void* _binary_data_txt_size;
const size_t len = (size_t)&_binary_data_txt_size;

void show_file(const char* name){
    FILE* file = fopen(name, "r");
    if (file == NULL){
        printf("Error (show_file): %s\n", name);
        return;
    }

    while (true){
        char ch = fgetc(file);
        if (feof(file) )
            break;
        putchar( ch );
    }
    printf("\n");

    fclose(file);
}

int main(){

    int fpipe[2];
    pipe(fpipe);

    if( !fork() ){
        for( int buffsize = len, done = 0; buffsize>done; ){
            done += write( fpipe[1], &_binary_data_txt_start + done, buffsize-done );
        }
        _exit(0);
    }

    close(fpipe[1]);
    char name[200];
    sprintf(name, "/proc/self/fd/%d", fpipe[0] );

    show_file(name);

    close(fpipe[0]);
}
在Windows上,我遇到以下编译器错误:

undefined reference to `_binary_data_txt_start'
undefined reference to `_binary_data_txt_end'

我试图用i386-pc-mingw32替换elf32-i386,但仍然得到相同的错误。

使用
nm data.o
查看符号的名称。可能是文件系统的差异导致文件名派生符号不同(例如文件名大写)


编辑:刚刚看到你的第二个问题。如果您使用的是线程,则可以制作一个管道并将其传递到库中(如果需要
文件*
,请首先使用
fdopen()
)。如果您对API有更具体的了解,我可以给您提供更具体的建议

我认为要使用MinGW,您需要从.c文件中的名称中删除前导下划线。有关详细信息,请参阅

查看使用以下选项是否有帮助:

extern char binary_data_txt_start;
extern char binary_data_txt_end;

如果您需要相同的源代码来为Linux或MinGW构建工作,则可能需要使用预处理器,以便在不同的环境中使用正确的名称

如果您使用的库需要一个
文件*
来读取数据,那么您可以使用从内存块中创建一个伪文件。这将避免在磁盘上创建临时文件。不幸的是,它是一个GNU扩展,所以我不知道它是否在MinGW中可用(可能不可用)


但是,大多数编写良好的库(如和)都提供了从内存而不是从磁盘打开文件的例程。尤其是libpng,它甚至提供了一个流接口,您可以在PNG文件完全读入内存之前对其进行增量解码。例如,如果您正在从网络流式传输隔行扫描的PNG,并且希望在加载时显示隔行扫描的数据以获得更好的用户体验,则此功能非常有用。

在Windows上,您可以将自定义资源嵌入到可执行文件中。您需要一个
.RC
文件和一个资源编译器。使用VisualStudioIDE,您可以轻松地完成此任务

在代码中,可以使用
FindResource
LoadResource
LockResource
函数在运行时将内容加载到内存中。将资源读取为长字符串的示例代码:

void GetResourceAsString(int nResourceID, CStringA &strResourceString)
{
    HRSRC hResource = FindResource(NULL, MAKEINTRESOURCE(nResourceID),  L"DATA");

    HGLOBAL hResHandle = LoadResource(NULL, hResource);

    const char* lpData = static_cast<char*> ( LockResource(hResHandle) );

    strResourceString.SetString(lpData, SizeofResource(NULL, hResource));

    FreeResource(hResource);
}
void GetResourceAsString(int-nResourceID、CStringA和strResourceString)
{
HRSRC hResource=FindResource(NULL,MAKEINTRESOURCE(nResourceID),L“DATA”);
HGLOBAL hResHandle=LoadResource(NULL,hResource);
const char*lpData=static_cast(锁资源(hResHandle));
SetString(lpData,SizeofResource(NULL,hResource));
免费资源(hResource);
}

其中
nResourceID
是自定义资源类型
数据下的资源ID
。数据只是一个名称,您可以选择其他名称。其他内置资源包括游标、对话框、字符串表等。

我创建了一个名为的小型库,它提供了一个简单的接口,用于提取/引用使用
objcopy
嵌入的节。这允许您将偏移量/大小传递给另一个工具,或使用文件描述符从运行时直接引用它。希望这将有助于未来的人


值得一提的是,这种方法比编译成符号更有效,因为它允许外部工具引用数据,而无需提取数据,也不需要将整个二进制文件加载到内存中才能提取/引用数据。

这似乎与嵌入式计算无关。重新标记。您是否愿意对您如何解决其他问题做一个简短的评论。我想知道:)我对一个我不能/不想“修复”的第三方库使用了类似的管道技巧。至于效率,这对我来说是很有效率的:我不经常给图书馆打电话,这至少节省了我一天的工作。@Kaos,看Michael Burr的回答。@Squall:啊,好的。评论中的措辞让我相信你已经解决了这个问题。
fmemopen
自2008年以来就是POSIX的一部分。但据我所知,它在Windows中不可用。
extern char binary_data_txt_start;
extern char binary_data_txt_end;
void GetResourceAsString(int nResourceID, CStringA &strResourceString)
{
    HRSRC hResource = FindResource(NULL, MAKEINTRESOURCE(nResourceID),  L"DATA");

    HGLOBAL hResHandle = LoadResource(NULL, hResource);

    const char* lpData = static_cast<char*> ( LockResource(hResHandle) );

    strResourceString.SetString(lpData, SizeofResource(NULL, hResource));

    FreeResource(hResource);
}