关于linux:将数据嵌入C程序中

关于linux:将数据嵌入C程序中

Embed data in a C++ program

我有一个使用SQLite的C程序。我想将SQL查询存储在一个单独的文件中-纯文本文件而不是源代码文件-但要将该文件像资源一样嵌入到可执行文件中。

(这必须在Linux上运行,因此就我所知,我无法将其存储为实际资源,尽管如果是Windows,那将是完美的。)

有没有简单的方法可以做到这一点,或者它是否实际上需要我为Linux编写自己的资源系统? (很容易,但是会花费更长的时间。)


您可以使用objcopy将文件的内容绑定到程序可以使用的符号。例如,请参阅此处以获取更多信息。


您始终可以编写一个小程序或脚本,以将文本文件转换为头文件并在构建过程中运行它。


使用宏。从技术上讲,该文件将是源代码文件,但看起来不是这样。
示例:

1
2
3
4
5
6
7
8
9
10
11
//queries.incl - SQL queries
Q(SELECT * FROM Users)
Q(INSERT [a] INTO Accounts)


//source.cpp
#define Q(query) #query,
char * queries[] = {
#include"queries.incl"
};
#undef Q

稍后,您可以在同一个文件上对该文件进行各种其他处理,例如您想拥有它们的数组和哈希映射,则可以重新定义Q来完成另一项工作并完成它。


这是我们用于跨平台文件嵌入的示例。
这非常简单,但可能会为您工作。

您可能还需要在escapeLine函数中更改其处理换行的方式。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
#include <string>
#include <iostream>
#include <fstream>
#include <cstdio>

using namespace std;

std::string escapeLine( std::string orig )
{
    string retme;
    for (unsigned int i=0; i<orig.size(); i++)
    {
        switch (orig[i])
        {
        case '\\\':
            retme +="\\\\\";
            break;
        case '
"':
            retme +="
\\\"";
            break;
        case '\
'
: // Strip out the final linefeed.
            break;
        default:
            retme += orig[i];
        }
    }
    retme +="\\\
"
; // Add an escaped linefeed to the escaped string.
    return retme;
}

int main( int argc, char ** argv )
{
    string filenamein, filenameout;

    if ( argc > 1 )
        filenamein = argv[ 1 ];
    else
    {
        // Not enough arguments
        fprintf( stderr,"Usage: %s <file to convert.mel> [ <output file name.mel> ]\
"
, argv[0] );
        exit( -1 );
    }

    if ( argc > 2 )
        filenameout = argv[ 2 ];
    else
    {
        string new_ending ="_mel.h";
        filenameout = filenamein;
        std::string::size_type pos;
        pos = filenameout.find(".mel" );
        if (pos == std::string::npos)
            filenameout += new_ending;
        else
            filenameout.replace( pos, new_ending.size(), new_ending );
    }

    printf("Converting "%s" to "%s"\
"
, filenamein.c_str(), filenameout.c_str() );

    ifstream filein( filenamein.c_str(), ios::in );
    ofstream fileout( filenameout.c_str(), ios::out );

    if (!filein.good())
    {
        fprintf( stderr,"Unable to open input file %s\
"
, filenamein.c_str() );
        exit( -2 );
    }
    if (!fileout.good())
    {
        fprintf( stderr,"Unable to open output file %s\
"
, filenameout.c_str() );
        exit( -3 );
    }

    // Write the file.
    fileout <<"tempstr =";

    while( filein.good() )
    {
        string buff;
        if ( getline( filein, buff ) )
        {
            fileout <<""" << escapeLine( buff ) <<""" << endl;
        }
    }

    fileout <<";" << endl;

    filein.close();
    fileout.close();

    return 0;
}

这有点丑陋,但您始终可以使用类似以下的内容:

1
2
3
4
5
const char *query_foo =
#include"query_foo.txt"

const char *query_bar =
#include"query_bar.txt"

其中query_foo.txt将包含带引号的查询文本。


我已经看到可以通过将资源文件转换为C源文件来完成,只定义了一个以十六进制格式包含资源文件内容的char数组(以避免出现恶意字符问题)。然后,可以自动编译此自动生成的源文件并将其链接到项目。

实现转换器为每个资源文件转储C文件以及编写一些访问资源的外观函数应该非常容易。


推荐阅读