如果对这个问题有明显的答案,请原谅我;我没有找到它,因为我不完全确定我在寻找什么。这可能是重复的一个我没有找到的问题;遗憾。
我有一个C可执行文件,它使用文本,音频,视频,图标和各种不同的文件类型。这些文件存储在本地;文件夹结构很大很深,需要与应用程序一起安装才能正常运行(不是我预计它会被分发,我希望自己打包工作以方便使用)。
在我看来,如果文件库存储在应用程序仍可访问的单个文件中,例如在/usr/bin/APPLICATION
旁边或在最合适的位置,则会更方便;可执行文件在需要时访问。
我搜索了类似的问题并找到了一些建议,指出了两个可能的选项 Resource Files ,这些选项似乎是Windows原生的, Including files at compile 。第一个问题导致类似于第二个问题的答案,并没有回答有关Linux可执行文件的资源文件存在的问题。它(像第二个)在编译过程中查看包含数据文件。这不是很有用,因为我只想更新我的资源,我不得不重新编译整个应用程序(媒体是动态添加的)。
问题:有没有办法将各种文件类型存储在linux中可执行文件可访问的单个文件中,如果是这样,您将如何实现?
我最初的想法是创建一个.zip
或.gz
文件,它也可以提供压缩作为额外的奖励,但我不知道如何(或者甚至可能)访问数据在这样的文件中即时。我同样不确定是否有特定的文件类型或库提供更合适的解决方案。另外我知道在Linux系统上这些文件中可以使用.dat
文件几乎一无所知吗?
答案 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