如何将文件嵌入可执行文件?

Ann*_*inn 25 c++ executable file

我有一个用C++编写的小型演示可执行文件,它只依赖于在运行之前加载的一个5kb PNG图像,用于我制作的像素文本.由于这个文件,我需要提供一个ZIP存档而不是只有一个可执行文件,这会在下载和"播放"之间产生足够的摩擦,我相信这会阻止一些人尝试它.

我的问题是,无论如何将PNG文件(以及任何其他文件)真正嵌入到可执行文件或源代码中,以便它是一个文件,并且可执行文件可以使用它吗?

我能够将PNG解析为字节流,因此不需要将其转换为像素数据.

提前致谢!(存在与此类似标题的其他问题,但他们和他们的答案似乎涉及更具体的问题,并且不是很有帮助)

编辑:编译器是Visual C++ 2010,这是在Windows上(虽然我想避免Windows特定的实用程序)

edit2:Alf的答案看起来像是最便携的方法,所以我很快写了一个函数来将PNG文件解析成TXT或头文件,可以读作unsigned char数组.它在这种形式下似乎与PNG文件本身相同,但我的png加载器不接受该数组.从内存加载时,PNG解析器会接受(void * buffer, size_t length)它是否重要.

代码,如果你想看,但如果你认为它们比这个方法更好,我仍会接受其他答案:

void compileImagePNGtoBinary(char * filename, char * output){

    FILE * file = fopen(filename, "rb");
    FILE * out = fopen(output, "w");

    unsigned char buffer[32];
    size_t count;
    fprintf(out, "#pragma once \n\n static unsigned char TEXT_PNG_BYTES[] = { ");
    while(!feof(file)){
            count = fread(buffer, 1, 32, file);

            for(int n = 0; n < count; ++n){
                    fprintf(out, "0x%02X, ", buffer[n]);
            };
    };
    fprintf(out, "};");
    fclose(file);
    fclose(out);

};
Run Code Online (Sandbox Code Playgroud)

最终编辑:Alf提到的ImageMagick正是我所需要的,谢谢!

Che*_*Alf 10

一种可移植的方法是定义一个类似的函数

typedef unsigned char Byte;

Byte const* pngFileData()
{
    static Byte const data =
    {
        // Byte data generated by a helper program.
    };
    return data;
}
Run Code Online (Sandbox Code Playgroud)

然后你所要做的就是编写一个小帮助程序,将PNG文件作为二进制文件读取,并生成C++花括号初始化文本.编辑:@awoodland在评论中指出,ImageMagick有这样一个小帮手程序......

当然,对于Windows特定的程序,而是使用普通的Windows资源方案.

干杯&hth.,


Rod*_*ddy 10

看看XD:

http://www.fourmilab.ch/xd/

最后,xd可以读取二进制文件并发出包含文件数据的C语言数据声明.当您希望在C程序中嵌入二进制数据时,这很方便.

就个人而言,我会使用Windows资源,但是如果你需要一种不涉及可执行格式知识的真正可移植的方式,那么这就是要走的路.PNG,JPG,无论......

  • 默认情况下,几乎所有shell中都有xxd -i,通常由vim软件包安装. (4认同)

fab*_*ioM 6

Base64编码文件并将其放在代码中的某个字符串中;)


Mar*_*som 6

您可以将任意文件嵌入到您的程序资源中:(MSDN) User-Defined Resource

用户定义的资源定义语句定义包含应用程序特定数据的资源。数据可以有任何格式,可以定义为给定文件的内容(如果给定文件名参数)或一系列数字和字符串(如果指定了原始数据块)。

nameID typeID filename
Run Code Online (Sandbox Code Playgroud)

文件名指定包含资源二进制数据的文件名。文件的内容作为资源包含在内。RC 不会以任何方式解释二进制数据。程序员有责任确保数据与目标计算机体系结构正确对齐。

完成后,您可以使用LoadResource 函数访问文件中包含的字节。


Nik*_*iou 5

为了完整性,我将提及#embed并希望这将“很快”成为(标准)现实。

C23(C,而不是 C++ 编程语言)已经合并了这样的功能作为语言特性,允许您编写:


int main (int, char*[]) {
    static const char sound_signature[] = {
#embed <sdk/jump.wav>
// ^^^^^^^^^^^^^^^^^^
    };
    static_assert((sizeof(sound_signature) / sizeof(*sound_signature)) >= 4,
        "There should be at least 4 elements in this array.");

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

对于 C++ 项目,拥有一个仅用于此用例的 C 子组件可能有点困难,除非您的应用程序强烈需要以某种方式嵌入数据。我的直觉是,即使在它进入标准之前,实现也会“悄悄地”让 C++ 可以使用它。您可以在该功能的作者博客(上面的示例借用于此)中阅读有关该主题的更多信息。

请记住,C++ 更早就追求完全相同的功能,但首先将其纳入 C 标准。此处提供了一篇论文(可能适用于 c++26),建议使用以下语法:

#include <embed>

constexpr std::span<const std::byte> fxaa_binary = std::embed("fxaa.spirv");
Run Code Online (Sandbox Code Playgroud)

即完全避免预处理器。