当我使用上面的程序解压apk文件的时候出现了问题,解压不出文件夹。
经过调试,发现apk文件在解压过程中,无法拿到apk文件中的目录信息,导致目录无法创建,目录中的文件也就无法解压了。
经过排查,我将判断apk文件中的当前项目是否是文件夹的逻辑修改了:使用当前的fileName_WithPath,解析出当前文件夹的路径,然后创建。但是这样做文件夹倒是创建出来了,不过全部是乱码,而且很多信息是错误的,创建出的文件夹的名称中包含无效的编码等信息。
我将apk文件和能正常解压缩出文件夹的zip文件的十六进制做了比较,发现在文件头部的压缩版本字段,apk是0x0800,也就是8,表示是Deflate,而zip是0x0000,也就是0,表示是uncompressed。
但是经过查看zlib的源代码,并没有发现能够解决这个问题的答案。
最后,我发现,当我将目录结构手动创建好,就能够成功解压了。
于是我对代码进行了修改:
#include <iostream>
#include <cstring>
#include <fstream>
#include <dirent.h>
#include <sys/stat.h>
#include <sys/types.h>
#include "unzip.h"
#include <zlib.h>
using namespace std;
void mymkdir(char * file_Path)
{
DIR *dp;
if ((dp = opendir(file_Path)) == NULL)
{
int err = mkdir(file_Path,S_IRWXU|S_IRWXG|S_IROTH);
if(err!=0)
{
int end=strlen(file_Path);
char *p=&file_Path[end-1];
while ((*p) != '/')
{
p--;
}
int length=(int)strlen(file_Path)-(int)strlen(p);
char *temp=new char[length];
memcpy(temp,file_Path,length);
mymkdir(temp);
err = mkdir(file_Path,S_IRWXU|S_IRWXG|S_IROTH);
}
}
closedir(dp);
}
int makedirectory(unzFile zfile,char *extractdirectory)
{
unsigned int fileName_BufSize=516;
char *fileName_WithPath=new char[fileName_BufSize];
char *file_Path=new char[fileName_BufSize];
char *p,*fileName_WithoutPath;
unz_file_info64 zFileInfo;
if (UNZ_OK != unzGetCurrentFileInfo64(zfile, &zFileInfo, fileName_WithPath, fileName_BufSize, NULL, 0, NULL, 0))
{
return -1;
}
char *temp = new char[fileName_BufSize];
strcpy(temp,extractdirectory);
strcat(temp,fileName_WithPath);
fileName_WithPath = temp;
p = fileName_WithoutPath = fileName_WithPath;
while ((*p) != '\0')
{
if (((*p) == '/') || ((*p) == '\\'))
fileName_WithoutPath = p + 1;
p++;
}
int length=(int)strlen(fileName_WithPath)-(int)strlen(fileName_WithoutPath);
memcpy(file_Path,fileName_WithPath,length);
mymkdir(file_Path);
}
int extract_currentfile(unzFile zfile,char *extractdirectory)
{
unsigned int fileName_BufSize=516;
char *fileName_WithPath=new char[fileName_BufSize];
char *p,*fileName_WithoutPath;
unz_file_info64 zFileInfo;
if (UNZ_OK != unzGetCurrentFileInfo64(zfile, &zFileInfo, fileName_WithPath, fileName_BufSize, NULL, 0, NULL, 0))
{
return -1;
}
char *temp = new char[fileName_BufSize];
strcpy(temp,extractdirectory);
strcat(temp,fileName_WithPath);
fileName_WithPath = temp;
p = fileName_WithoutPath = fileName_WithPath;
while ((*p) != '\0')
{
if (((*p) == '/') || ((*p) == '\\'))
fileName_WithoutPath = p + 1;
p++;
}
if (UNZ_OK != unzOpenCurrentFile(zfile))
{
return -2;
}
fstream file;
file.open(fileName_WithPath, ios_base::out | ios_base::binary);
ZPOS64_T fileLength = zFileInfo.uncompressed_size;
char *fileData = new char[fileLength];
//解压缩文件
ZPOS64_T err = unzReadCurrentFile(zfile, (voidp)fileData, fileLength);
if (err<0)
{
return -3;
}
file.write(fileData, fileLength);
file.close();
free(fileData);
return 0;
}
int main()
{
unzFile zfile;
char filepath[]="./test.apk";
zfile=unzOpen64(filepath);
if(zfile==NULL)
{
cout<<"[ERROR] 文件不存在"<<endl;
return -1;
}
else
{
cout << "[INFO] 成功打开压缩文件:" <<filepath<< endl;
}
unz_global_info64 zGlobalInfo;
if (UNZ_OK != unzGetGlobalInfo64(zfile, &zGlobalInfo))
{
cout << "[ERROR] 获取压缩文件全局信息失败" << endl;
return -1;
}
for (int i = 0; i < zGlobalInfo.number_entry; i++)
{
int err = makedirectory(zfile, (char *)"extract/");
unzCloseCurrentFile(zfile);
unzGoToNextFile(zfile);
}
unzGoToFirstFile (zfile);
for (int i = 0; i < zGlobalInfo.number_entry; i++)
{
int err = extract_currentfile(zfile, (char *)"extract/");
unzCloseCurrentFile(zfile);
unzGoToNextFile(zfile);
}
cout<<"[INFO] 解压完成" << endl;
return 0;
}
简单的说就是实现了一个创建文件夹的函数makedirectory,首先调用该函数创建好目录结构,然后再次解压。不过这样做导致解压时间稍微有点增加,但是时间还是比较短的。