#define CHUNK_SIZE 4096
class CZipFileStream {
// zlib支持.
z_stream m_stream;
int m_last_inflate_;
// 解压缓冲.
char m_zlib_buffer[CHUNK_SIZE];
// 输入的字节数.
std::size_t m_zlib_buffer_size;
std::ifstream& m_fs;
bool m_auto_close_fs;
public:
/// <summary>
/// 构造一个解压类
/// </summary>
/// <param name="fs">输入的文件流</param>
/// <param name="autoClosefs">是否自动关闭文件,默认不自动关闭</param>
CZipFileStream(std::ifstream& fs,bool autoClosefs=false) :m_fs(fs), m_auto_close_fs(autoClosefs), m_last_inflate_(Z_OK)
{
memset(&m_stream, 0, sizeof(z_stream));
//inflateInit(&m_stream);
}
~CZipFileStream()
{
if (m_stream.zalloc)
inflateEnd(&m_stream);
if (m_auto_close_fs && m_fs.is_open())
m_fs.close();
}
int Read(BYTE* buf, std::size_t bufsize)
{
if (!m_fs.is_open())
{
m_last_inflate_ = Z_DATA_ERROR;
return 0;
}
if (IsBadReadPtr(buf, bufsize) || buf == 0)
{
m_last_inflate_ = Z_BUF_ERROR;
return 0;
}
if (!m_stream.zalloc)
{
m_last_inflate_ = inflateInit(&m_stream);
if (m_last_inflate_ != Z_OK)
{
return m_last_inflate_;
}
}
m_stream.next_out = (Bytef*)buf;
m_stream.avail_out = bufsize;
while (!m_fs.eof()|| m_stream.avail_in)
{
if (m_stream.avail_in == 0)
{
m_fs.read(m_zlib_buffer, CHUNK_SIZE);
m_zlib_buffer_size = m_fs.gcount();
m_stream.avail_in = (uInt)m_zlib_buffer_size;
m_stream.next_in = (z_const Bytef*) & m_zlib_buffer[0];
}
//没有数据读出来。
if (m_zlib_buffer_size == 0)
{
if (m_stream.zalloc)
{
inflateEnd(&m_stream);
m_last_inflate_ = Z_STREAM_END;
}
break;
}
m_last_inflate_ = inflate(&m_stream, Z_SYNC_FLUSH);
//解压完了就不管输出是否满了
if (m_last_inflate_ == Z_STREAM_END)
{
if (m_auto_close_fs)
m_fs.close();
if (m_stream.zalloc)
inflateEnd(&m_stream);
return bufsize-m_stream.avail_out;
}
//如果解压成功又没有填满输出则继续读数据
else if (m_last_inflate_ == Z_OK)
{
if (m_stream.avail_out)
continue;
else
return bufsize-m_stream.avail_out;
}
else
{//到这说明出错了
if (m_stream.zalloc)
{
if (m_auto_close_fs)
m_fs.close();
inflateEnd(&m_stream);
}
break;
}
}
return 0;
}
//判断文件是否解压完成
bool Eof()
{
return (m_last_inflate_ == Z_STREAM_END || m_last_inflate_!=Z_OK);
}
//正常情况下解压完成了都应该是Z_STREAM_END ,此函数可以判断解压的数据最后是否成功
bool IsOk()
{
return (m_last_inflate_ == Z_STREAM_END );
}
//直接解压所有的数据,需要提前知道需要的缓冲大小。
static bool UnCompress(const BYTE* pcCompBuf, uLong ulCompLen, BYTE* pcUnCompBuf, uLong& uncomprLen)
{
if (pcCompBuf == NULL)
{
return false;
}
int err = uncompress(pcUnCompBuf, &uncomprLen, (const Bytef*)pcCompBuf, ulCompLen);
if (err != Z_OK)
{
return false;
}
return true;
}
};
调用大概如下。代码初步测试通过。静态函数UnCompress是一次解压所有数据。可以用它验证解压数据,但是它的缓冲区需要留得足够大。
std::ifstream infile(inputPath.c_str(), std::ios_base::binary | std::ios_base::in);
CZipFileStream zipstreame(infile,true);
std::vector<BYTE> outbuf;
while (!zipstreame.Eof())
{
BYTE buf[1024];
int readcount = zipstreame.Read(buf, sizeof(buf));
outbuf.insert(outbuf.end(), buf, buf + readcount);
}