如何使用Minizip(基于Zlib)?

16

我正试图为一个跨平台应用程序归档文件,而Minizip(基于zlib构建)似乎是最具可移植性的压缩软件。

然而,当我尝试运行以下虚拟代码时,我会得到系统错误 [我的可执行文件]已停止工作。Windows可以在线检查问题的解决方案。

有人能帮我看看如何使用这个库吗? - (我找不到任何文档或教程)

zip_fileinfo zfi;

int main()
{
    zipFile zf = zipOpen("myarch.zip",APPEND_STATUS_ADDINZIP);
    int ret = zipOpenNewFileInZip(zf,
        "myfile.txt",
        &zfi,
        NULL,   0,
        NULL,   0,
        "my comment for this interior file",
        Z_DEFLATED,
        Z_NO_COMPRESSION
        );
    zipCloseFileInZip(zf);
    zipClose(zf, "my comment for exterior file");
    return 0;
}

规格: Msys + MinGW,Windows 7,使用来自zlib125dll.zip/dll32的zlibwapi.dll

3个回答

24

我通过谷歌找到了这个问题,但它没有包含任何完整可行的代码。因此,我在此为未来的访问者提供一些代码。

int CreateZipFile (std::vector<wstring> paths)
{
    zipFile zf = zipOpen(std::string(destinationPath.begin(), destinationPath.end()).c_str(), APPEND_STATUS_CREATE);
    if (zf == NULL)
        return 1;

    bool _return = true;
    for (size_t i = 0; i < paths.size(); i++)
    {
        std::fstream file(paths[i].c_str(), std::ios::binary | std::ios::in);
        if (file.is_open())
        {
            file.seekg(0, std::ios::end);
            long size = file.tellg();
            file.seekg(0, std::ios::beg);

            std::vector<char> buffer(size);
            if (size == 0 || file.read(&buffer[0], size))
            {
                zip_fileinfo zfi = { 0 };
                std::wstring fileName = paths[i].substr(paths[i].rfind('\\')+1);

                if (S_OK == zipOpenNewFileInZip(zf, std::string(fileName.begin(), fileName.end()).c_str(), &zfi, NULL, 0, NULL, 0, NULL, Z_DEFLATED, Z_DEFAULT_COMPRESSION))
                {
                    if (zipWriteInFileInZip(zf, size == 0 ? "" : &buffer[0], size))
                        _return = false;

                    if (zipCloseFileInZip(zf))
                        _return = false;

                    file.close();
                    continue;
                }
            }
            file.close();
        }
        _return = false;
    }

    if (zipClose(zf, NULL))
        return 3;

    if (!_return)
        return 4;
    return S_OK;
}

1
这很好。但有几个问题:1. 这假设整个文件都可以放入内存,这有点简单化了,但对于这个示例来说可能足够了。2. 如果初始文件长度为0,则没有理由将0长度文件输出视为错误。3. 假设这是一个错误,就不需要三元操作符。即 if (zipWriteInFileInZip(zf, size == 0 ? "" : &buffer[0], size)) 可以写成 if (zipWriteInFileInZip(zf, &buffer[0], size))。4. 我建议不要使用下划线前缀。我知道你在它后面使用了小写字母,但... 耸肩 - Adrian
你提出的第二点和第三点是错误的。size==0的检查是为了确保缓冲区[0]在长度为零时不会被执行。if语句中的逻辑或运算然后确保零长度文件被正确地写入到zip文件中,后面的三元操作符再次确保缓冲区[0]在长度为零时不会被调用。代码正常工作并按预期工作。 - niemiro
2
这被标记为C语言,而不是C++。 - Neil Roy
有一些打字错误。应该写 Z_OK,而不是在 COM 中使用的 S_OK - Yogurt
2
@Yogurt 实际上应该是来自 zip.h 或 unzip.h 中的 ZIP_OK 或 UNZ_OK。 - RobinP

4

minizip库附带了示例代码; minizip.c 用于压缩,miniunz.c 用于解压缩。这两个命令行实用程序展示了如何使用该库,但它们的代码很混乱。

你还需要填写 zfi zip_fileinfo。至少应将结构体初始化为零。 zfi 包含有关使用 zipOpenNewFileInZip 存储文件 "myfile.txt" 的信息。该结构应包含文件的日期和属性。

我建议使用 PKWARE Desktop 诊断 zip 问题。它显示 ZIP 文件中文件的结构/属性以及 ZIP 文件本身。当我打开 myarch.zip 时,它告诉我存在错误。我深入研究了文件属性,并发现属性不正确。


1
感谢您的调查,但在上面的代码示例中,zfi 不应该在我指定它的情况下初始化为零吗?由于它在任何函数之外,所以它在堆栈上,对吗? - JellicleCat
啊,是的,你说得对。我只是把你的代码放进一个函数里看看它是否能正常工作。 - Nathan Moinvaziri
1
你的代码应该正常工作。我没有遇到任何Windows崩溃的情况。这可能与使用DLL有关。你尝试过在zlib库中编译吗? - Nathan Moinvaziri
zfi不在堆上,堆是动态分配的内存,例如通过malloc获得。在*NIX上,zfi在BSS中,这确实被初始化为零。从概念上讲,可执行文件中的所有BSS段都指定了它的加载地址和长度。 - Mike Crawford

2

minizip库有很好的文档。只需打开zip.h文件查看详细信息。

我可以告诉你,你可能已经传递了错误的参数给zipOpen函数。(APPEND_STATUS_ADDINZIP需要一个现有的zip文件!)

此外,请检查zipOpen函数是否返回有效的zipFile句柄。


谢谢。我将我的第二个参数更改为APPEND_STATUS_CREATE。我在zip.h中没有看到任何关于有效性的参考;那么,我是否应该检查zipfile是否为NULL - JellicleCat
此外,您能否解释一下 extrafield_localextrafield_global 应该是什么?我没有找到任何示例或足够的描述。 - JellicleCat
我以前从未使用过extrafield_local和extrafield_global。很抱歉,我无法提供帮助。如果您的zip.h文件中没有文档,您可以下载zlib源代码。我相信该软件包中的zip.h文件包含了很好的文档。 - Rango
1
是的,您可以检查zf是否为NULL来确定它是否是一个有效的zipFile句柄。 - Nathan Moinvaziri
2
很抱歉要说,但minizip远远不足以被称为良好文档的近义词。事实上,它完全相反。 - Javier Quevedo
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接