C - 将大量文件存储为单个资源

时间:2015-08-21 23:09:09

标签: c linux file

如果对这个问题有明显的答案,请原谅我;我没有找到它,因为我不完全确定我在寻找什么。这可能是重复的一个我没有找到的问题;遗憾。

我有一个C可执行文件,它使用文本,音频,视频,图标和各种不同的文件类型。这些文件存储在本地;文件夹结构很大很深,需要与应用程序一起安装才能正常运行(不是我预计它会被分发,我希望自己打包工作以方便使用)。

在我看来,如果文件库存储在应用程序仍可访问的单个文件中,例如在/usr/bin/APPLICATION旁边或在最合适的位置,则会更方便;可执行文件在需要时访问。

我搜索了类似的问题并找到了一些建议,指出了两个可能的选项 Resource Files ,这些选项似乎是Windows原生的, Including files at compile 。第一个问题导致类似于第二个问题的答案,并没有回答有关Linux可执行文件的资源文件存在的问题。它(像第二个)在编译过程中查看包含数据文件。这不是很有用,因为我只想更新我的资源,我不得不重新编译整个应用程序(媒体是动态添加的)。

问题:有没有办法将各种文件类型存储在linux中可执行文件可访问的单个文件中,如果是这样,您将如何实现?

我最初的想法是创建一个.zip.gz文件,它也可以提供压缩作为额外的奖励,但我不知道如何(或者甚至可能)访问数据在这样的文件中即时。我同样不确定是否有特定的文件类型或库提供更合适的解决方案。另外我知道在Linux系统上这些文件中可以使用.dat文件几乎一无所知吗?

4 个答案:

答案 0 :(得分:3)

我不明白你为什么要使用单个文件。考虑到文件提取的增加的复杂性(以及增加错误的可能性)以及相关的开销,我看不出它会如何更方便"。

  

我有一个C可执行文件,它使用文本,音频,视频,图标和各种不同的文件类型。

许多其他Linux应用程序也是如此。使用包管理时,常规方法是将/usr/bin/YOURAPP中的应用程序/usr/share/YOURAPP/和体系结构相关数据(如帮助程序二进制文件)中的体系结构独立数据(图标,音频,视频等)放在一起在/usr/lib/YOURAPP。后两者极为常见的是完整的目录树,有时候很深和很宽。

对于本地编译的内容,通常将它们放在/usr/local/bin/YOURAPP/usr/local/share/YOURAPP//usr/local/share/YOURAPP/中,以避免混淆包管理器。 (如果您检查./configure脚本或阅读Makefile,这是他们支持的PREFIX变量的主要目的。)

/usr/bin/YOURAPP通常是一个简单的shell脚本,设置环境变量或检查特定于用户的覆盖(来自$HOME/.YOURAPP/),最后是exec /usr/lib/YOURAPP/YOURAPP.bin [parameters...],它将shell替换为实际的二进制可执行文件而不将shell留在内存中。

例如,我机器上的/usr/share/octave/包含总共138个目录(层次结构中最多7个目录深)和1463个文件;大约10兆的东西"全都告诉了。 LibreOffice,Eagle,Fritzing和KiCAD各占数百兆,所以Octave也不是一个极端的例子。

答案 1 :(得分:1)

你有几种选择(TODO:添加更多;)):

您可以阅读一些归档文件格式规范,编写代码以读取/写入这些归档文件,并浪费您的时间。

你可以发明一种肮脏的简单文件格式,例如(" dsa"代表" Dirty and Simple Archiver"):

#include <stdint.h>

// Located at the beginning of the file    
struct DSAHeader {
    char            magic[3];            // Shall be (char[]) { 'D', 'S', 'A' }
    unsigned char   endianness;          // The rest of the file is translated according to this field. 0 means little-endian, 1 means big-endian.
    unsigned char   checksum[16];         // MD5 sum of the whole file. (when calculating checksums, this field is psuedo-filled with zeros).
    uint32_t        fileCount;
    uint32_t        stringTableOffset;   // A table containing the files' names.
};

// A dsaHeader.fileCount-sized array of DSAInodeHeader follows the DSAHeader.
struct DSANodeHeader {
    unsigned char   type;              // 0 means directory, 1 means regular file.
    uint32_t        parentOffset;      // Pointer to the parent directory, or zero if the node is in the root.
    uint32_t        offset;            // The node's type-dependent header starts here.
    uint32_t        nodeSize;          // In bytes for files, and in number of entries for directories.
    uint32_t        dataOffset;        // The file's data starts at this offset for files, and a pointer to the first DSADirectoryEntryHeader for directories.
    uint32_t        filenameOffset;    // Relative to the string table.
};

typedef uint32_t    DSADirectoryEntryHeader;    // Offset to the entry's DSANodeHeader

&#34;字符串表&#34;是一个连续的以null结尾的字符串序列。

这种格式非常简单(便携;))。而且,作为奖励,如果您想要(de)压缩,您可以使用Zip,BZ2或XZ之类的东西来(压缩)压缩文件(这些程序/格式与归档程序无关,即不依赖于tar,如通常认为)。

作为最后一个(或第一个?)手段,您可以使用现有的库/ API来操作存档器和压缩文件格式。

编辑:添加了对目录的支持:)。

答案 2 :(得分:1)

  
    

我有一个C可执行文件,它使用文本,音频,视频,图标和各种不同的文件类型。这些文件存储在本地;文件夹结构很大很深,需要与应用程序一起安装才能正常运行。

  

考虑到相关的不同文件类型的复杂性以及文件夹结构的大而深,并且需要与应用程序一起安装。如果您想动态更改资源,添加单个资源文件将很困难,或者说几乎无法跟踪更改。当然,向可执行文件添加资源不是一种选择,因为它会增加可执行文件的大小,并且在更新资源的情况下需要频繁的重新编译。

在考虑了项目的所有方面后,在我看来解决方案将使用INI文件。 INI将存储在确定的位置,其他资源位置应该在INI文件中存放。与INI一样,您可以轻松存储资源,散列键和大小的位置,并可以轻松检查更改或更新资源。

由于您使用的是已压缩的文件类型版本,因此General Zipping算法无法正常工作,因为速率非常低。因此建议使用7z algos进行压缩。从各种算法我建议选择xz压缩算法,因为它目前被许多开源项目用来压缩二进制文件并减小大小。

Foreach文件压缩其crc32或哈希值也应包含在INI文件中,以检查传输数据的有效性。

答案 3 :(得分:0)

让我们说:

top-level-folder/
  |
   - your-linux-executable
   - icon-files-folder/
   - image-files-folder/
   - other-folders/
   - other-files

这样做(在top-level-folder内)

tar zcvf my-package.tgz top-level-folder

要展开,请执行以下操作:

tar zxvf my-package.tgz