首页 > 解决方案 > 使用 Chilkat 将内存缓冲区写入 Zip 而不使用副本

问题描述

我正在研究Chilkat Zip 库以将二进制数据转储到磁盘以供以后重用。我要转储的 blob 可能非常大(10+ GiB),因此复制其中任何一个都是浪费时间和空间。

我已经找到了CkByteData::borrowData允许我让 Chilkat 使用应用程序分配的缓冲区而不是将其复制到内部分配的缓冲区中的方法。但是,当将它添加CkByteDataCkZipEntry(使用CkZipEntry::AppendData)时,我注意到我的应用程序突然消耗了两倍的内存;一个明显的迹象表明 Chilkat 确实进行了复制。之后CkZip::WriteZip,内存消耗恢复正常。

我用于测试的片段:

int main(int, char**)
{
    CkZip zip;
    zip.UnlockComponent(/* hidden */);
    zip.NewZip("data.zip");

    constexpr auto size = 20'000'000; // ~= 20 MiB
    auto data = new char[size];

    for (auto i = 0; i < size; ++i)
       data[i] = static_cast<char>(i);

    CkByteData bd;
    bd.borrowData(data, size);

    auto entry = zip.AppendNew("blob");
    entry->AppendData(bd);
    // --> Memory consumption jumps to ~40 MiB

    delete entry;

    zip.WriteZip();
    // --> Memory consumption drops to ~20 MiB

    delete[] data;
    return 0;
}

我的问题:

注意:我实际上不需要压缩数据(但这是一个很好的加分项)。因此,如果解决方案需要禁用压缩,那很好。

标签: c++chilkat

解决方案


如果 zip 中的新文件可能很大,唯一的解决方案是删除现有条目,然后调用 AppendOneFileOrDir 以添加新文件。您不想尝试将 10GB 文件读入内存并添加它。当您调用 AppendOneFileOrDir 时,它实际上并没有将文件读入内存。相反,它会创建一个引用文件的 zip 条目(请参阅http://www.chilkatsoft.com/refdoc/csZipEntryRef.html#prop10)当调用 WriteZipAndClose 时,要压缩的数据从文件中流式传输,因此它永远不会完全驻留在记忆中。


推荐阅读