使用minzi解压zip
简介
,一个轻量的 zlib (RFC 1950) and Deflate (RFC 1951) 实现库。
一种在 Windows 下的实现
miniz 配置
头文件
#pragma once
#include <memory>
class MY_Zip {
public:
MY_Zip();
virtual ~MY_Zip();
bool unzip(const char* in, const char* out);
const char* error();
int code();
private:
class Impl;
std::unique_ptr<Impl> m_pImpl;
};
.h 实现
#include "MY_Zip.h"
#include "miniz.h"
#include <iostream>
#include <string>
#include <vector>
#include <windows.h>
#include <memory>
#include <ShlObj_core.h>
class MY_Zip::Impl {
public:
std::string errMsg;
int errCode;
bool IsDirectory(const std::string& path) {
std::string name = path;
return !name.empty() && (name.back() == '/' || name.back() == '\\');
}
bool CreateDirectory(const std::string& path) {
int result = SHCreateDirectoryExW(NULL, string2wstring(path).c_str(), NULL);
return result == ERROR_SUCCESS || result == ERROR_ALREADY_EXISTS;
}
private:
std::string wstring2string(const std::wstring& wstr) {
int size_needed = WideCharToMultiByte(CP_UTF8, 0, wstr.c_str(), -1, NULL, 0, NULL, NULL);
std::string str(size_needed - 1, 0);
WideCharToMultiByte(CP_UTF8, 0, wstr.c_str(), -1, &str[0], size_needed, NULL, NULL);
return str;
}
std::wstring string2wstring(const std::string& str) {
int size_needed = MultiByteToWideChar(CP_UTF8, 0, str.c_str(), -1, NULL, 0);
std::wstring wstr(size_needed - 1, 0);
MultiByteToWideChar(CP_UTF8, 0, str.c_str(), -1, &wstr[0], size_needed);
return wstr;
}
};
MY_Zip::MY_Zip() : m_pImpl(new Impl)
{
}
MY_Zip::~MY_Zip()
{
}
bool MY_Zip::unzip(const char* in, const char* out)
{
mz_zip_archive archive{};
if (!mz_zip_reader_init_file(&archive, in, 0)) {
m_pImpl->errMsg = "can not open zip file: " + std::string(in);
std::cerr << m_pImpl->errMsg << std::endl;
return false;
}
int file_cnt = (int)mz_zip_reader_get_num_files(&archive);
if (file_cnt == 0) {
m_pImpl->errMsg = "zip file is empty";
std::cerr << m_pImpl->errMsg << std::endl;
return false;
}
for (int i = 0; i < file_cnt; ++i) {
mz_zip_archive_file_stat file_stat;
if (!mz_zip_reader_file_stat(&archive, i, &file_stat)) {
m_pImpl->errMsg = "can't get file infomation in zip";
mz_zip_reader_end(&archive);
return false;
}
std::string path = std::string(out) + "\\" + file_stat.m_filename;
if (m_pImpl->IsDirectory(path)) {
m_pImpl->CreateDirectory(path);
continue;
}
size_t last_slash = path.find_last_of("/\\");
if (last_slash != std::string::npos) {
m_pImpl->CreateDirectory(path.substr(0, last_slash));
}
if (!mz_zip_reader_extract_to_file(&archive, i, path.c_str(), 0)) {
m_pImpl->errMsg = "unzip failed " + path;
m_pImpl->errCode = archive.m_last_error;
std::cerr << m_pImpl->errMsg << std::endl;
mz_zip_reader_end(&archive);
return false;
}
}
mz_zip_reader_end(&archive);
m_pImpl->errMsg = "";
std::cout << "unzip complete." << std::endl;
return true;
}
const char* MY_Zip::error()
{
return m_pImpl->errMsg.c_str();
}
int MY_Zip::code()
{
return m_pImpl->errCode;
}
使用:
string tempLatestFile = ANSItoUTF8(strLatestFile.GetBuffer());
string tempLatestFolder = ANSItoUTF8(strLatestFolder.GetBuffer());
hjZip.unzip(tempLatestFile.c_str(), tempLatestFolder.c_str())
其中路径转换:
string UTF8toANSI(const std::string& instr) //utf-8-->ansi
{
int MAX_STRSIZE = instr.length() * 2 + 2;
WCHAR* wcharstr = new WCHAR[MAX_STRSIZE];
memset(wcharstr, 0, MAX_STRSIZE);
MultiByteToWideChar(CP_UTF8, 0, (char*)instr.data(), -1, wcharstr, MAX_STRSIZE);
char* charstr = new char[MAX_STRSIZE];
memset(charstr, 0, MAX_STRSIZE);
WideCharToMultiByte(CP_ACP, 0, wcharstr, -1, charstr, MAX_STRSIZE, NULL, NULL);
string charstrtemp(charstr);
delete []wcharstr;
delete []charstr;
return charstrtemp;
}
string ANSItoUTF8(const std::string& instr) //ansi-->utf-8
{
int MAX_STRSIZE = instr.length() * 2 + 2;
WCHAR* wcharstr = new WCHAR[MAX_STRSIZE];
memset(wcharstr, 0, MAX_STRSIZE);
MultiByteToWideChar(CP_ACP, 0, (char*)instr.data(), -1, wcharstr, MAX_STRSIZE);
char* charstr = new char[MAX_STRSIZE];
memset(charstr, 0, MAX_STRSIZE);
WideCharToMultiByte(CP_UTF8, 0, wcharstr, -1, charstr, MAX_STRSIZE, NULL, NULL);
CString charstrtemp(charstr);
delete[] wcharstr;
delete[] charstr;
return (LPCSTR)charstrtemp;
}
一种 Linux 下的实现
使用 C++17 的 filesystem
CMakeLists.txt 配置(使用 git clone
获取对应的 miniz 项目):
cmake_minimum_required(VERSION 3.10)
project(test)
set(CMAKE_CXX_STANDARD 17)
add_subdirectory(vendor/miniz)
add_executable(test main.cpp MY_Zip.h MY_Zip.cpp)
target_link_libraries(test miniz)
代码部分改动实现即可:
#include "MY_Zip.h"
#include "miniz.h"
#include <iostream>
#include <string>
#include <memory>
#include <filesystem>
namespace fs = std::filesystem;
class MY_Zip::Impl {
public:
std::string errMsg;
int errCode;
bool IsDirectory(const std::string& path) {
return !path.empty() && (path.back() == '/' || path.back() == '\\');
}
bool CreateDirectory(const std::string& path) {
std::error_code ec;
return fs::create_directories(fs::path(path), ec) || ec.value() == 0;
}
};
MY_Zip::MY_Zip() : m_pImpl(new Impl) {}
MY_Zip::~MY_Zip() {}
bool MY_Zip::unzip(const char* in, const char* out) {
mz_zip_archive archive{};
if (!mz_zip_reader_init_file(&archive, in, 0)) {
m_pImpl->errMsg = "can not open zip file: " + std::string(in);
std::cerr << m_pImpl->errMsg << std::endl;
return false;
}
int file_cnt = static_cast<int>(mz_zip_reader_get_num_files(&archive));
if (file_cnt == 0) {
m_pImpl->errMsg = "zip file is empty";
std::cerr << m_pImpl->errMsg << std::endl;
mz_zip_reader_end(&archive);
return false;
}
for (int i = 0; i < file_cnt; ++i) {
mz_zip_archive_file_stat file_stat;
if (!mz_zip_reader_file_stat(&archive, i, &file_stat)) {
m_pImpl->errMsg = "can't get file info in zip";
mz_zip_reader_end(&archive);
return false;
}
fs::path targetPath = fs::path(out) / file_stat.m_filename;
if (m_pImpl->IsDirectory(file_stat.m_filename)) {
m_pImpl->CreateDirectory(targetPath.string());
continue;
}
fs::path parentDir = targetPath.parent_path();
m_pImpl->CreateDirectory(parentDir.string());
if (!mz_zip_reader_extract_to_file(&archive, i, targetPath.string().c_str(), 0)) {
m_pImpl->errMsg = "unzip failed: " + targetPath.string();
m_pImpl->errCode = archive.m_last_error;
std::cerr << m_pImpl->errMsg << std::endl;
mz_zip_reader_end(&archive);
return false;
}
}
mz_zip_reader_end(&archive);
m_pImpl->errMsg = "";
std::cout << "unzip complete." << std::endl;
return true;
}
const char* MY_Zip::error() {
return m_pImpl->errMsg.c_str();
}
int MY_Zip::code() {
return m_pImpl->errCode;
}
comment:
- Valine
- LiveRe
- ChangYan