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

C-将大量文件存储为单个资源,c,linux,file,C,Linux,File,如果这个问题有一个显而易见的答案,请原谅我;我没有找到它,因为我不完全确定我在找什么。这很可能是我没有发现的重复问题;对不起 我有一个C可执行文件,它使用文本、音频、视频、图标和各种不同的文件类型。这些文件存储在本地;文件夹结构又大又深,需要与应用程序一起安装才能正确运行(我并不期望它被分发,我希望为方便起见打包自己的工作) 我个人认为,如果将文件库存储在应用程序可以访问的单个文件中,例如与/usr/bin/application一起或存储在最合适的位置,会更方便;在需要时由可执行文件访问 我搜

如果这个问题有一个显而易见的答案,请原谅我;我没有找到它,因为我不完全确定我在找什么。这很可能是我没有发现的重复问题;对不起

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

我个人认为,如果将文件库存储在应用程序可以访问的单个文件中,例如与
/usr/bin/application
一起或存储在最合适的位置,会更方便;在需要时由可执行文件访问

我搜索了一些类似的问题,并找到了一些建议,指出了两个可能的选项,它们似乎是Windows和所固有的。第一个问题给出了与第二个问题类似的答案,但没有回答与linux可执行文件资源文件的存在相关的问题。它(像第二个)着眼于在编译过程中包含数据文件。如果我只想更新我的资源,而被迫重新编译整个应用程序(媒体是动态添加的),那么这就没有那么有用了

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


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

我不明白您为什么要使用单个文件。考虑到文件提取增加的复杂性(以及漏洞潜入的可能性增加)和相关的开销,我不认为这会“更方便”

我有一个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
s,这就是它们支持的
前缀
变量的主要用途。)

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


例如,我的机器上的
/usr/share/octave/
总共包含138个目录(在多达7个目录的层次结构中)和1463个文件;总共大约有10兆字节的“东西”。LibreOffice、Eagle、Fritzing和KiCAD各占用数百兆字节,因此倍频程在任何方面都不是一个极端的例子。

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

您可以阅读一些archiver文件格式规范,编写代码来读/写这些archiver,这样做会浪费您的时间

您可以发明一种肮脏、简单的文件格式,例如(“dsa”代表“肮脏、简单的归档程序”):

#包括
//位于文件的开头
结构DSAHeader{
char magic[3];//应该是(char[]){'D','S','A'}
unsigned char endianness;//文件的其余部分根据此字段进行转换。0表示小尾端,1表示大尾端。
无符号字符校验和[16];//整个文件的MD5和。(计算校验和时,此字段用零填充)。
uint32_t文件计数;
uint32\u t stringTableOffset;//包含文件名的表。
};
//dsaHeader后面跟着一个dsaHeader.fileCount大小的dsaNodeHeader数组。
结构DSANodeHeader{
无符号字符类型;//0表示目录,1表示常规文件。
uint32\u t parentOffset;//指向父目录的指针,如果节点位于根目录中,则为零。
uint32_ut offset;//节点的类型相关标头从这里开始。
uint32_t nodeSize;//文件以字节为单位,目录以条目数为单位。
uint32_t dataOffset;//对于文件,文件的数据从该偏移量开始,对于目录,指向第一个DSADirectoryEntryHeader的指针。
uint32\u t filenameOffset;//相对于字符串表。
};
typedef uint32\u t数据目录头;//偏移到条目的DSAndeHeader
“字符串表”是以null结尾的字符串的连续序列

这种格式非常简单(而且便于携带)。另外,如果您想要(反)压缩,您可以使用Zip、BZ2或XZ之类的工具来(反)压缩您的文件(这些程序/格式是archiver agn)
#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
top-level-folder/
  |
   - your-linux-executable
   - icon-files-folder/
   - image-files-folder/
   - other-folders/
   - other-files
tar zcvf my-package.tgz top-level-folder
tar zxvf my-package.tgz