代码之家  ›  专栏  ›  技术社区  ›  Head Geek

在C++程序中嵌入数据

  •  18
  • Head Geek  · 技术社区  · 16 年前

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

    (这必须在Linux上运行,所以据我所知,我不能将其存储为实际资源,尽管如果它适用于Windows,那将是完美的。)

    有什么简单的方法可以做到这一点吗?或者它会有效地要求我为Linux编写自己的资源系统吗?(这很容易做到,但需要更长的时间。)

    6 回复  |  直到 9 年前
        1
  •  24
  •   moonshadow    16 年前

    您可以使用objcopy将文件内容绑定到程序可以使用的符号。例如, here 了解更多信息。

        2
  •  3
  •   Trent    16 年前

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

    //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来做另一项工作并完成它。

        3
  •  3
  •   vava    16 年前

    您始终可以编写一个小程序或脚本,将文本文件转换为头文件,并将其作为构建过程的一部分运行。

        4
  •  2
  •   tfinniga    16 年前

    这是我们用于跨平台嵌入文件的示例。 这很简单,但可能对你有效。

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

    #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 '\n': // Strip out the final linefeed.
                break;
            default:
                retme += orig[i];
            }
        }
        retme += "\\n"; // 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> ]\n", 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\"\n", 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\n", filenamein.c_str() );
            exit( -2 );
        }
        if (!fileout.good())
        {
            fprintf( stderr, "Unable to open output file %s\n", 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;
    }
    
        5
  •  1
  •   introp    16 年前

    它有点难看,但你总是可以使用这样的东西:

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

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

        6
  •  0
  •   Matej    16 年前

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

    为每个资源文件实现转储C文件的转换器应该很容易,也可以编写一些facade函数来访问资源。