如何读取zip包中的文件

shuaitian1992 2016-12-14 10:36:40
是这样的,我现在想在程序中读取zip包中的文件,不能解压到磁盘上,而是直接读取,zip包中可能有文件夹,文件夹里有文件,通过给定的文件全路劲名称读取zip包中的文件。希望大神给点思路。。谢谢啦~
...全文
763 8 打赏 收藏 转发到动态 举报
写回复
用AI写文章
8 条回复
切换为时间正序
请发表友善的回复…
发表回复
shuaitian1992 2016-12-16
  • 打赏
  • 举报
回复
谢谢各位,我试试,嘿嘿
赵4老师 2016-12-15
  • 打赏
  • 举报
回复
libzip在linux上可以用吧。
shuaitian1992 2016-12-15
  • 打赏
  • 举报
回复
谢谢楼上的回答,忘了说我的程序是在linux上写的,所以不能借助win32 api
hongwenjun 2016-12-15
  • 打赏
  • 举报
回复
bool zip_extract_currentfile(unzFile uf, LPCTSTR save_filename)
{
    char szFilePathA[MAX_PATH];

    // 对于每个内部文件,可用 unzGetCurrentFileInfo64 来查内部文件名
    unz_file_info64 FileInfo;
    if (unzGetCurrentFileInfo64(uf, &FileInfo, szFilePathA, sizeof(szFilePathA), NULL, 0, NULL, 0) != UNZ_OK) {
        return false;
    }

//    printf("%s", szFilePathA);  // 在压缩文件中的 文件名

    // 对于非目录的内部文件,用 unzOpenCurrentFile打开
    if (unzOpenCurrentFile(uf) != UNZ_OK) {
        return false;
    }

    HANDLE hFile = CreateFile(save_filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);

    if (hFile == INVALID_HANDLE_VALUE) {
        return false;
    }


    // 然后 unzReadCurrentFile 读取文件内容,写入到真实文件中。
    // unzReadCurrentFile 返回 0 表示文件读取结束然后 unzReadCurrentFile 读取文件内容,写入到真实文件中。
    // unzReadCurrentFile 返回 0 表示文件读取结束

    char byBuffer[WRITEBUFFERSIZE];
    while (true) {
        int err = unzReadCurrentFile(uf, byBuffer, WRITEBUFFERSIZE);

        if (err < 0) {
            return false;
        } else if (err == 0) {
            break;
        } else {
            DWORD dwWritten = 0;

            if (!WriteFile(hFile, byBuffer, (DWORD)err, &dwWritten, NULL) || dwWritten != (DWORD)err) {
                return false;
            }
        }
    }

    CloseHandle(hFile);
    return true;
}



bool zip_extract_onefile(const char* zip_filename, const char* filename , const char* save_filename)
{
    // 解压先使用 zipOpen64 来打开一个 ZIP 文件
    unzFile uf = unzOpen64(zip_filename);

//    // 需要先使用 unzGetGlobalInfo64 来取得该文件的一些信息,来了解这个压缩包里一共包含了多少个文件,等等。
//    unz_global_info64 gi;
//
//    if (unzGetGlobalInfo64(uf, &gi) != UNZ_OK) {
//        return false;
//    }

    // 尝试zip文件中找到该文件szFileName。
    int err = UNZ_OK;
    if (unzLocateFile(uf, filename, CASESENSITIVITY) != UNZ_OK) {
//       printf("file %s not found in the zipfile\n", filename);
        return false;
    }

    if (!zip_extract_currentfile(uf, save_filename)) {
        return false;
    }

    unzClose(uf);
    return true;
}


// 查阅: http://www.cppblog.com/Streamlet/archive/2013/05/12/127368.html

/*  相关 API
 * 压缩相关:
 * zipOpen64   zipClose    zipOpenNewFileInZip zipCloseFileInZip   zipWriteInFileInZip
 *
 * 解压相关:
 * unzOpen64   unzClose    unzGetGlobalInfo64  unzGoToNextFile
 * unzGetCurrentFileInfo64 unzOpenCurrentFile  unzCloseCurrentFile unzReadCurrentFile
 *
 * 首先是压缩操作。使用 zipOpen64 来打开/创建一个 ZIP 文件,然后开始遍历要被放到压缩包中去的文件。
 * 针对每个文件,先调用一次 zipOpenNewFileInZip,然后开始读原始文件数据,使用 zipWriteInFileInZip 来写入到 ZIP 文件中去。
 * zipOpenNewFileInZip 的第三个参数是一个 zip_fileinfo 结构,该结构数据可全部置零,其中 dosDate 可用于填入一个时间(LastModificationTime)。
 * 它的第二个参数是 ZIP 中的文件名,若要保持目录结构,该参数中可以保留路径,如 foo/bar.txt。
 *
 * 解压操作稍微复杂一点点。打开一个 ZIP 文件后,需要先使用 unzGetGlobalInfo64 来取得该文件的一些信息,来了解这个压缩包里一共包含了多少个文件,等等。
 * 目前我们用得着的就是这个文件数目。然后开始遍历 ZIP 中的文件,初始时自动会定位在第一个文件,以后处理完一个后用 unzGoToNextFile 来跳到下一个文件。
 * 对于每个内部文件,可用 unzGetCurrentFileInfo64 来查内部文件名。这个文件名和刚才 zipOpenNewFileInZip 的第二个参数是一样的形式,所以有可能包含路径。
 * 也有可能会以路径分隔符(/)结尾,表明这是个目录项(其实压缩操作的时候也可以针对目录写入这样的内部文件,上面没有做)。所以接下来要根据情况创建(多级)目录。
 * unzGetCurrentFileInfo64 的第三个参数是 unz_file_info64 结构,其中也有一项包含了 dosDate 信息,可以还原文件时间。
 * 对于非目录的内部文件,用 unzOpenCurrentFile,打开,然后 unzReadCurrentFile 读取文件内容,写入到真实文件中。unzReadCurrentFile 返回 0 表示文件读取结束。
 *
 */

赵4老师 2016-12-15
  • 打赏
  • 举报
回复
7zip据说是开源且跨平台的。
hongwenjun 2016-12-15
  • 打赏
  • 举报
回复
确切的说,ZLib 可能并不是一个针对 ZIP 文件的库,它只是一个针对 gzip 以及 deflate 算法的库。它提供了一个叫做 minizip (contrib\minizip) 例子来给出操作 ZIP 文件的方法 局限性 只能压缩、解压采用 deflate 算法的 ZIP 文件。(不过此类 ZIP 应该占了绝大多数) 由于 minizip 中相关 API 的限制,以及 ZIP 文件格式的限制,被压缩/解压的相关文件名必须与系统的当前代码页相符合。(虽然 ZIP 格式最近一次更新加入了使用 UTF8 编码文件名的选项,但是不能保证所遇到的 ZIP 文件都是新格式的,minizip 中似乎也没有针对此选项做什么动作。)
hongwenjun 2016-12-15
  • 打赏
  • 举报
回复
引用 3 楼 shuaitian1992 的回复:
谢谢楼上的回答,忘了说我的程序是在linux上写的,所以不能借助win32 api
你要的数据在这个缓存里,你只要把写文件的 winapi 删除掉就可以了 char byBuffer[WRITEBUFFERSIZE]; 上面代码使用的 zlib 库, 你可以下载 zlib库 里面有个 minzip 示例
paschen 版主 2016-12-14
  • 打赏
  • 举报
回复

64,651

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧