前言:呃,今天上来翻了翻之前写的文章,其中访问率最高的是那个『自绘RadioButton』,有好多人留言让我发源代码,这,也是自己懒惰,现在已经把源代码的连接补到文章最后,也是CSDN的下载,希望对某些人有帮助吧,呵呵。看着之前自己写的东西还挺有意思的,特别是那个用JAVA做的地图编辑器的学习版,其实是到后面写不下去了,觉得越想越复杂。其实自己最近闲暇时分用MFC写了个『Descent: Journey To The Dark!』的地图编辑器,下次整理整理发上来好了。这几年因为工作一直很忙,说实话也没啥多的技术积累,毕竟公司里面混饭吃,还是要做一些杂活,虽然感觉也做得久了点。好了,言归正传,这次的东西是关于从ZIP压缩包中读取文件的方法。其实也是那个地图编辑器要用的一个小功能。使用了Zlib库中contrib中的minizip的代码,有兴趣的童鞋可以去下Zlib源码看下,我是没这个闲情雅致,只是实用派的。之前也在网上搜了好久,大多都是介绍如何使用Zlib库压缩和解压数据,唯独就是没几多人介绍如何从ZIP Archive中抽取文件的。不过也可能是我太急功近利了,只是想找抽取的代码,而不想一步一步看人家的介绍。正好昨天找了点资料,自己捣鼓了下,把这抽取的代码写了下,可能有些人也正急着找也不一定(当然,我觉得像我这种从头写地图编辑器的奇葩估计也不多了,网上大把的类库可以用)。不过也正好,把抽取的方法写成了个动态库,还做了lua的封装导出,这样C++和Lua就都能用了,写得比较简单,只是介绍个方法,其他功能还有待扩展,这里只是个例子可以参考下实现的方案,因为代码中好多都是测试用的,并且错误处理基本没有做,以后再慢慢完善吧。代码随便用,本来就是个测试版的东西,出事儿了别找我就行。
// The following ifdef block is the standard way of creating macros which make exporting
// from a DLL simpler. All files within this DLL are compiled with the ZEXTRACT_EXPORTS
// symbol defined on the command line. this symbol should not be defined on any project
// that uses this DLL. This way any other project whose source files include this file see
// ZEXTRACT_API functions as being imported from a DLL, wheras this DLL sees symbols
// defined with this macro as being exported.
#ifdef ZEXTRACT_EXPORTS
#define ZEXTRACT_API __declspec(dllexport)
#else
#define ZEXTRACT_API __declspec(dllimport)
#endif
#include "MemBuffer.h"
#include "luna.hpp"
ZEXTRACT_API void ListZip(const char* fname);
ZEXTRACT_API bool FindFileInZip(const char* zfn, const char* fname);
ZEXTRACT_API int GetFileInZip(CMemBuffer& buffer, const char* zfn, const char* fname, const char* password);
extern "C" ZEXTRACT_API int luaopen_zextract(lua_State* L);
讲下
GetFileInZip函数。一共有4个入参:
ZEXTRACT_API int GetFileInZip(CMemBuffer& buffer, const char* zfn, const char* fname, const char* password)
{
unzFile uf = unzOpen(zfn);
if (NULL == uf)
{
printf("unzOpen failed...\n");
return -1;
}
int err = unzLocateFile(uf, fname, 0);
if (UNZ_OK != err)
{
printf("GetFileInZip unzLocateFile failed... error:%d\n");
return err;
}
unz_file_info file_info;
char filename_inzip[256];
err = unzGetCurrentFileInfo(uf, &file_info, filename_inzip, sizeof(filename_inzip), NULL, 0, NULL, 0);
if (UNZ_OK != err)
{
printf("unzGetCurrentFileInfo failed... error:%d\n", err);
return err;
}
err = unzOpenCurrentFilePassword(uf, password);
if (UNZ_OK != err)
{
printf("unzOpenCurrentFilePassword failed... error:%d\n", err);
return err;
}
char* pBuff = new char[file_info.uncompressed_size];
if (pBuff == NULL)
{
unzCloseCurrentFile(uf);
unzClose(uf);
return -2;
}
err = unzReadCurrentFile(uf, pBuff, file_info.uncompressed_size);
if (err < 0)
{
printf("unzReadCurrentFile failed... error:%d\n", err);
delete [] pBuff;
unzCloseCurrentFile(uf);
unzClose(uf);
return err;
}
// Append data to the MemBuffer
buffer.Append(pBuff, file_info.uncompressed_size);
unzCloseCurrentFile(uf);
unzClose(uf);
return err;
}
其中关键的操作函数就只有7个:
unzOpen
|
打开Archive文件 |
unzClose | 关闭Archive文件 |
unzGetCurrentFileInfo | 获取当前选择的内部压缩文件的信息 |
unzLocateFile | 定位文件 |
unzOpenCurrentFilePassword | 选择打开当前文件 |
unzReadCurrentFile | 读取当前文件 |
unzCloseCurrentFile | 关闭当前文件 |
// MemBuffer.h: interface for the CMemBuffer class.
//
//////////////////////////////////////////////////////////////////////
#if !defined(AFX_MEMBUFFER_H__36D0136D_B57A_49FF_855B_E5545078B130__INCLUDED_)
#define AFX_MEMBUFFER_H__36D0136D_B57A_49FF_855B_E5545078B130__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
class CMemBuffer
{
public:
CMemBuffer(int nInitLen = 16);
CMemBuffer(const char* pData, int nLen = 0);
CMemBuffer(const CMemBuffer& buff);
virtual ~CMemBuffer();
public:
virtual int GetBufferLen();
virtual bool Append(const char* pData, int nLen = 0);
virtual char* GetBuffer();
protected:
bool ReAllocBuffer(int nDeltaLen);
protected:
char* m_pBuffer; // buffer data
int m_nCurLen;
int m_nMaxLen;
};
#endif // !defined(AFX_MEMBUFFER_H__36D0136D_B57A_49FF_855B_E5545078B130__INCLUDED_)
这个实现没什么好讲的,拿到数据只要Append即可。要获取数据直接使用
GetBuffer()即可。
//////////////////////////////////////////////////////////////////////////
// @Param
// zipName which archive
// fileName which file to extract from the archive named zipName's value
// password password to extract file from zip
// @Return
// binary data
// error number
static int luacf_getFileInZip(lua_State* L)
{
CMemBuffer buff;
const char* pZipName = luaL_checkstring(L, 1);
const char* pFileName = luaL_checkstring(L, 2);
const char* pPassword = lua_tostring(L, 3);
int ret = GetFileInZip(buff, pZipName, pFileName, pPassword);
if (ret >= 0)
{
lua_pushlstring(L, buff.GetBuffer(), buff.GetBufferLen());
return 1;
}
lua_pushnil(L);
lua_pushnumber(L, ret);
return 2;
}
const struct luaL_reg libs[] =
{
{"getFileInZip", luacf_getFileInZip},
{NULL, NULL}
};
ZEXTRACT_API int luaopen_zextract(lua_State* L)
{
luaL_register(L, "zextract", libs);
return 1;
}
这部分就没啥好说了,总之就是这么简单。
-- 是否是debug版本
local bDGB = false;
local zlib;
if bDGB then
zlib = package.loadlib("zextract_d.dll", "luaopen_zextract");
if type(zlib) == "function" then
zlib = zlib();
end
else
zlib = require "zextract";
end
if type(zlib) ~= "table" then
print("loadlib error");
return
end
print(zlib.getFileInZip("readme.zip", "folder/readme.txt", "123456"))