不用解压,直接读取zip中指定的文件,例如文件/sdcard/a.zip中有文件z.txt,读取步骤如下:
int zfd = zip_open("/sdcard/a.zip/z.txt");
if (ZIP_IS_VALID(zfd)) {
zip_seek(zfd, 5, SEEK_SET);
zip_read(zfd, buf, 10);
zip_close(zfd);
}
2.目前只支持以“存储“格式压缩的zip文件;
3.主要接口:
int zip_open(const char* path);
int zip_close(int handle);
int zip_read(int handle, void *buf, int count);
int zip_seek(int fd, int offset, int whence);
int zip_stat(const char *file_name, struct stat *buf);
/*
* read a file in zip as normal file.
* only support kCompressStored method
*
* dependent on android ZipFileRO.h
* build in AOSP
*
* zip_open
* zip_close
* zip_read
* zip_seek
* zip_stat
*/
#ifndef _ZIP_WRAPPER_H_
#define _ZIP_WRAPPER_H_
#include
#include
#include
#include
#include
#include
#ifdef __cplusplus
extern "C" {
#endif
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG,LOG_TAG,__VA_ARGS__)
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__)
#define LOGW(...) __android_log_print(ANDROID_LOG_WARN,LOG_TAG,__VA_ARGS__)
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__)
#define LOGF(...) __android_log_print(ANDROID_LOG_FATAL,LOG_TAG,__VA_ARGS__)
#define ZIP_IS_VALID(f) ((f) != 0)
int zip_open(const char* path);
int zip_close(int handle);
int zip_read(int handle, void *buf, int count);
int zip_seek(int fd, int offset, int whence);
int zip_stat(const char *file_name, struct stat *buf);
#ifdef __cplusplus
}
#endif
#endif //#ifndef _ZIP_WRAPPER_H_
#define LOG_TAG "zip_wrapper"
#include
#include "zip_wrapper.h"
using namespace android;
extern "C" {
#define ZIP_FLAG ".zip/"
#define ZIP_FLAG_LEN strlen(ZIP_FLAG)
static int is_file(const char* path)
{
int ok = 0;
struct stat buf;
int ret = stat(path, &buf);
if (ret == 0) {
if (S_ISREG(buf.st_mode)) {
ok = 1;//is file
} else {
//LOGI("%s is not a file !", path);
}
} else {
LOGI("%s is not exist ! ret = %d", path, ret);
}
return ok;
}
static int is_dir(const char* path)
{
int ok = 0;
struct stat buf;
int ret = stat(path, &buf);
if (ret == 0) {
if (S_ISDIR(buf.st_mode)) {
ok = 1;//is dir
} else {
//LOGI("%s is not a dir !", path);
}
} else {
LOGI("%s is not exist !", path);
}
return ok;
}
static int get_zip_path(const char* path, char* zippath)
{
int ok = 0;
const char* p = NULL;
p = strstr(path, ZIP_FLAG);
if (p && (p + ZIP_FLAG_LEN != path + strlen(path))) {
if (zippath) {
strncpy(zippath, path, p + ZIP_FLAG_LEN - 1 - path);
LOGI("zip path: %s", zippath);
} // else, just judge the path is ok
ok = 1;
}
return ok;
}
static int get_path_in_zip(const char* path, char* pathinzip)
{
int ok = 0;
const char* p = NULL;
p = strstr(path, ZIP_FLAG);
if (p && (p + ZIP_FLAG_LEN != path + strlen(path))) {
if (pathinzip) {
strcpy(pathinzip, p + ZIP_FLAG_LEN);
//LOGI("path in zip: %s", pathinzip);
} // else, just judge the path is ok
ok = 1;
}
return ok;
}
// whether or not the file is in zip
// /xxx/a.zip/b.txt return true if a.zip is a file, else false
// /xxx/a.zip/ return false
// /xxx/a.zip return false
// /xxx/a.txt return false
//
int is_in_zip(const char* path)
{
int iszip = 0;
struct stat buf;
char zippath[PATH_MAX] = {0};
if (path == NULL) {
LOGE("is_in_zip() path is null !");
return iszip;
}
int ret = stat(path, &buf);
//LOGI("PATH_MAX = %d", PATH_MAX);
LOGI("path: %s", path);
if (ret < 0) { // failed, maybe /xxx/a.zip/b.txt or no exist
if (get_zip_path(path, zippath)) {
if (is_file(zippath)) {
LOGI("%s is in zip: %s", path, zippath);
iszip = 1; // OK
} else {
LOGI("%s is not a zip", zippath);
}
} else {
LOGI("%s is not exist!", path);
}
} else {
if (S_ISDIR(buf.st_mode)) {
LOGI("%s is a dir", path);
} else if (S_ISREG(buf.st_mode)) {
LOGI("%s is a file", path);
} else {
LOGI("%s not a file or dir", path);
}
}
return iszip;
}
/******************************************************************/
typedef struct _zip_priv {
ZipFileRO * zip;
ZipEntryRO entry;
FileMap * map;
off_t offset;
}zip_priv;
static zip_priv * _zip_priv_open(const char * path)
{
char zippath[PATH_MAX] = {0};
char filepath[256] = {0};
get_zip_path(path, zippath);
get_path_in_zip(path, filepath);
int fd = 0;
zip_priv * zp = NULL;
ZipFileRO * zip = new ZipFileRO();
ZipEntryRO entry = NULL;
FileMap* map = NULL;
do
{
if (zip->open(zippath) != NO_ERROR) {
LOGE("zip->open(%s) failed!", zippath);
break;
}
entry = zip->findEntryByName(filepath);
if (entry == 0) {
LOGE("zip->findEntryByName(%s) failed!", filepath);
break;
}
int method = 0;
if (!zip->getEntryInfo(entry, &method, 0, 0, 0, 0, 0)) {
LOGE("zip->getEntryInfo() failed!");
break;
}
// only support stored method
if (method != ZipFileRO::kCompressStored) {
LOGE("error: not support, method = %d !\n"
"only support kCompressStored", method);
break;
}
map = zip->createEntryFileMap(entry);
if (map == 0) {
LOGE("zip->createEntryFileMap(%p) failed!", entry);
break;
}
zp = (zip_priv *)malloc(sizeof(zip_priv));
if (zp == NULL) {
LOGE("malloc(sizeof(zip_priv)) failed !");
break;
}
memset(zp, 0, sizeof(zip_priv));
zp->zip = zip;
zp->entry = entry;
zp->map = map;
zp->offset = 0;
fd = (int)zp; //ok
}while(0);
if (fd == 0) {
if (map) map->release();
if (zip) delete zip;
if (zp) free(zp);
LOGI("_zip_open(%s) failed !", path);
} else {
LOGI("_zip_open(%s) ok !", path);
}
return zp;
}
static int _zip_open(const char * path)
{
return (int)_zip_priv_open(path);
}
static int _zip_close(int handle)
{
int ret = -1;
zip_priv * zp = (zip_priv*)handle;
if (zp) {
zp->map->release();
delete zp->zip;
free(zp);
ret = 0;
}
return ret;
}
static ssize_t _zip_read(int handle, void *buf, size_t count)
{
int ret = -1;
zip_priv * zp = (zip_priv*)handle;
if (zp) {
size_t max = zp->map->getDataLength() - zp->offset;
max = max < count ? max : count;
if (max > 0) {
memcpy(buf, ((char *)zp->map->getDataPtr()) + zp->offset, max);
zp->offset += max;
}
ret = max;
}
return ret;
}
static off_t _zip_seek(int handle, off_t offset, int whence)
{
int ret = -1;
zip_priv * zp = (zip_priv*)handle;
off_t _offset, datalen;
if (zp) {
_offset = zp->offset;
datalen = zp->map->getDataLength();
switch(whence) {
case SEEK_SET:
_offset = offset;
break;
case SEEK_CUR:
_offset += offset;
break;
case SEEK_END:
_offset = datalen + offset;
break;
default:
LOGE("_zip_seek not support whence: %d", whence);
break;
}
if (_offset != zp->offset) {
_offset = _offset >= 0 ? _offset : 0;
zp->offset = _offset <= datalen ? _offset : datalen;
}
ret = zp->offset;
}
return ret;
}
/*
buf->st_size
buf->st_mode & S_IFREG
buf->st_mode & S_IFDIR
buf->st_mtime
*/
static int _zip_stat(const char *file_name, struct stat *buf)
{
int ret = -1;
zip_priv * zp = _zip_priv_open(file_name);
do
{
if (zp == NULL) {
break;
}
memset(buf, 0, sizeof(struct stat));
size_t uncompLen = 0;
if (!zp->zip->getEntryInfo(zp->entry, 0, &uncompLen, 0, 0, 0, 0)) {
LOGE("zp->zip->getEntryInfo() failed !");
break;
}
LOGI("uncompLen = %d", uncompLen);
buf->st_size = uncompLen;
char name[256] = {0};
if (zp->zip->getEntryFileName(zp->entry, name, sizeof(name)) == -1) {
LOGE("zp->zip->getEntryFileName() failed !");
break;
}
if (name[strlen(name) - 1] == '/') {
buf->st_mode = S_IFDIR;
LOGI("%s is a dir", name);
} else {
buf->st_mode = S_IFREG;
LOGI("%s is a file", name);
}
buf->st_mtime = 0;
ret = 0;
}while(0);
if (zp) {
_zip_close((int)zp);
}
return ret;
}
/******************************************************************/
typedef struct _fs_operator {
int (*close)(int handle);
ssize_t (*read) (int handle, void *buf, size_t count);
off_t (*seek) (int handle, off_t offset, int whence);
} fs_operator;
typedef struct _zip_info {
const fs_operator * opt;
int fd;
} zip_info;
static const fs_operator s_operator[] =
{
{
close,
read,
lseek,
},
{
_zip_close,
_zip_read,
_zip_seek,
},
};
/******************************************************************/
// api
int zip_open(const char* path)
{
int zfd = 0;
zip_info * pz = NULL;
if (path == NULL) {
LOGE("zip_open: path is null");
return -1;
}
do
{
pz = (zip_info *) malloc(sizeof(zip_info));
if (pz == NULL) {
LOGE("malloc(sizeof(zip_info)) failed !");
break;
}
memset(pz, 0, sizeof(zip_info));
int fd = 0;
if (is_in_zip(path)) {
fd = _zip_open(path);
if (!fd) {
break;
}
pz->opt = &s_operator[1];
} else {
fd = open(path, O_RDONLY);
if (fd < 0) {
LOGE("open(%s) failed!", path);
break;
}
pz->opt = &s_operator[0];
}
pz->fd = fd;
zfd = (int)pz;
}while(0);
if (!ZIP_IS_VALID(zfd)) {
if (pz) free(pz);
}
return zfd;
}
int zip_close(int handle)
{
int ret = -1;
zip_info * pz = (zip_info *)handle;
if (pz) {
ret = pz->opt->close(pz->fd);
free(pz);
}
return ret;
}
int zip_read(int handle, void *buf, int count)
{
int ret = -1;
zip_info * pz = (zip_info *)handle;
if (pz) {
ret = pz->opt->read(pz->fd, buf, count);
}
return ret;
}
int zip_seek(int handle, int offset, int whence)
{
int ret = -1;
zip_info * pz = (zip_info *)handle;
if (pz) {
ret = pz->opt->seek(pz->fd, offset, whence);
}
return ret;
}
int zip_stat(const char *file_name, struct stat *buf)
{
int ret = -1;
if(file_name && buf) {
if (is_in_zip(file_name)) {
ret = _zip_stat(file_name, buf);
} else {
ret = stat(file_name, buf);
}
} else {
}
return ret;
}
}//extern "C" {
#define LOG_TAG "zip_wrapper"
#include
#include
#include "zip_wrapper.h"
using namespace android;
extern "C" {
int is_in_zip(const char* path);
}
// ---------------------------------------------------------------------------
int testReadEntry(int argc, char** argv)
{
ZipFileRO mZip;
char path[256] = "/sdcard/zip/demo.zip";
if (argc >= 2) {
strcpy(path, argv[1]);
}
LOGI("path: %s\n", path);
mZip.open(path);
size_t numEntries = mZip.getNumEntries();
LOGI("numEntries: %d\n", numEntries);
if ((int)numEntries < 0){
return 0;
}
int method = 0;
size_t uncompLen = 0;
size_t compLen = 0;
off64_t offset = 0;
long modWhen = 0;
long crc32 = 0;
char name[256] = {0};
for (size_t i=0 ; i
LOCAL_PATH:= $(call my-dir)
#################################
include $(CLEAR_VARS)
LOCAL_SRC_FILES:= \
zip_wrapper.cpp
LOCAL_CFLAGS :=
LOCAL_SHARED_LIBRARIES := libutils
LOCAL_C_INCLUDES := .
LOCAL_MODULE_TAGS:= optional
LOCAL_MODULE:= libreadzip
include $(BUILD_STATIC_LIBRARY)
#################################
include $(CLEAR_VARS)
LOCAL_SRC_FILES:= \
zip_main.cpp
LOCAL_CFLAGS :=
LOCAL_STATIC_LIBRARIES := libreadzip
LOCAL_SHARED_LIBRARIES := libutils
LOCAL_C_INCLUDES := .
LOCAL_MODULE_TAGS:= optional
LOCAL_MODULE:= readzip
include $(BUILD_EXECUTABLE)