将文件夹转换为单个文件而不压缩它?

时间:2014-12-04 00:27:53

标签: c++ file directory archive

所以我的目标是创建一个自包含文件,其中包含要加载到3D场景中的所有资源。例如,会有一个文本文件详细说明模型的所有位置,旋转,比例等,然后是里面有模型和纹理的文件夹。这在文件夹中并不难做到,但为了简单起见,我希望将它全部放在一个文件中,避免压缩它并解压缩它。我不想压缩和解压缩它的原因是为了加快加载时间,因为这是为了游戏。

有没有办法做到这一点?或者我将不得不咬紧牙关把它变成拉链。

感谢。

4 个答案:

答案 0 :(得分:3)

您可以使用ZIP而不压缩或TAR。但这是一个更好的主意:压缩它。 CPU时间便宜。磁盘传输需要永远。大多数情况下,加载压缩数据并对其进行解压缩比加载未压缩数据更快。

答案 1 :(得分:1)

您可以创建没有压缩的ZIP文件。 ("存储"模式。)还有类似的包装存档程序,可用于从多个文件创建单个存档。 * nix系统上的TAR文件很受欢迎,还有很多其他文件。

此外,平衡将要解压缩的时间量与从磁盘加载(未压缩)文件所花费的时间量。很多时候,未压缩文件的磁盘读取时间比加载压缩文件并在内存中解压缩所花费的时间长。

答案 2 :(得分:1)

如果这是针对Windows应用程序的,则可以在.RC文件中使用用户定义的资源语句作为EXE或包含的DLL,这些DLL将从外部文件插入数据作为二进制资源。如果您只想分发依赖于其他文件中包含的数据的单个EXE文件,或者不希望将您可能存档和分发的文件与您的应用程序进行访问/可修改(没有一些工作),这将非常方便)由最终用户。

这非常简单 - 语法只是

nameID typeID filename

表示资源文件。您可以使用::FindResource()::LoadResource(). MS文档访问数据,用户定义的资源位于http://msdn.microsoft.com/en-us/library/windows/desktop/aa381054(v=vs.85).aspx

答案 3 :(得分:0)

原始问题的时机可能是偶然的。事实证明,在未来,我建议的查找/加载资源方法对我们来说也不是一个选项(之前我使用它的代码是跨平台的),所以我想出了一个也可能的解决方案为你工作。完整代码有点太多要发布作为SO答案(但请参阅我的后续评论),尽管您可以立即制作自己的快速版本。

基本上,我编写了一个实用程序,它只输出输出文件的基名argv[1](“ output-base-name ”),argv[2...(argc-1)]是输入文件。我打开output-base-name.cppoutput-base-name.h进行写入(如果存在则会覆盖)。

对于每个输入文件,生成器实用程序执行此操作:

1:根据文件名(“ generated_name ”)生成可变名称标识符 2:读取输入文件
3:将以下内容转储到output-base-name.cpp

static uint8_t generated_name[] = {
    // Initialize with contents of input file as a bunch of 0xNN, 0xNN... values.
};

并进入output-base-name.h,相应的

static const unsigned IDR_generated_name = N; // start at 0, see below re:range check

4:在最后一个输入文件之后,用

之类的内容完成 output-base-name.cpp
static struct {
    unsigned       ID;
    unsigned       size;  // I assume you aren't trying to embed files >4GB!
    const uint8_t* data;
} 
fileData[] = {
   // one array element for each input file
   { IDR_generated_name,  sizeof(generated_name), generated_name },
   ... 
};

const uint8_t* getResourceData(unsigned ID){
    // a real version would do a safer lookup/range check of some sort based on ID
    return fileData[ID].data;
}

unsigned getResourceSize(unsigned ID){
    // a real version would do a safer lookup/range check of some sort based on ID
    return fileData[ID].size;
}

5:完成 output-base-name.h 的原型,无论你的“获取”功能是什么样的,例如。

extern const uint8_t* getResourceData(unsigned ID);
extern unsigned getResourceSize(unsigned ID);

只需在需要访问数据的地方使用output-base-name.h并将output-base-name.cpp添加到makefile或项目中(使其依赖于二进制输入文件,使用构建规则中的生成器实用程序并{{ 1}}会在必要时自动为您重新生成它。如果你想要它们在某种动态库中,只需在你的“获取”函数中添加适当的导出属性。

让生成器将输出包装在命名空间中,如果你愿意,可以将基于类的接口放在一起(或者生成一个而不是示例“get”函数),并且你应该很好。

与使用未压缩的zip文件(甚至是我为Windows目标建议的嵌入式资源方法)相比,这种方法有几个优点:

  1. 在应用程序代码中处理起来要简单得多 - 不需要读取zip目录,提取文件数据等。
  2. 没有额外依赖另一个第三方库来查找/提取文件数据(假设你没有推出自己的zip库,这将会更加有效)
  3. 所有的解析和查找工作都是为您完成的 - 如果将数据粘贴到静态库或您的可执行文件中,则链接器已经解析了每个字节数组的地址,如果共享库或DLL,则由OS加载程序解析
  4. 您知道数据将存在或您的二进制文件无法运行(不是zip lib方法,甚至是Windows上的Find / LoadResource)
  5. 与一个zip文件相比,Joe User的数据更难以访问(因此更安全)
  6. 由于在应用程序加载过程中预先解析了数据地址,因此应该比zip或Windows资源方法更快
  7. 它还可以用于您希望随附(或提供给)应用程序的任何形式的相对静态数据 - 只需将文件打包到带有生成器的共享/动态库中,并使用生成的导出访问器函数。您甚至可以在以后(编译/发货时间之后)创建更新的或全新的数据包,并使用配置选项在运行时加载。
  8. 如果需要,它将在较旧的C ++编译器中工作(或者,无法生成任何命名空间或类包装器,甚至是普通的C语言)
  9. 这只是我使用的方法的一个示例,但它涵盖了所有基础知识,因此如果解决方案提前而不是更晚(再次,请参阅注释)对您更好,这可能就足够了(您可能想要范围检查“get”函数中的值 - 至少在调试版本中,可能使用某种容器而不是使用c样式的struct数组等。)