You do not need to decompress the package and directly read the specified file in the ZIP file. For example, the file/sdcard/a.zipcontains the file z.txt. The read procedure is as follows:
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);}
1. dependent on zipfilero. h In Android framework, which must be compiled in the Android system source code environment;
2. Currently, only ZIP files compressed in "Storage" format are supported;
3. Main interfaces:
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);
Zip_wrapper.h
/* * 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 <unistd.h>#include <sys/types.h>#include <sys/stat.h>#include <errno.h>#include <fcntl.h>#include <android/log.h>#ifdef __cplusplusextern "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_
Zip_wrapper.cpp
#define LOG_TAG "zip_wrapper"#include <utils/ZipFileRO.h>#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 methodif (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_sizebuf->st_mode & S_IFREGbuf->st_mode & S_IFDIRbuf->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, },};/******************************************************************/ // apiint 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" {
Zip_main.cpp
#define LOG_TAG "zip_wrapper"#include <utils/String8.h>#include <utils/ZipFileRO.h>#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<numEntries ; i++) { ZipEntryRO entry = mZip.findEntryByIndex(i); if (mZip.getEntryFileName(entry, name, sizeof(name)) == 0) { if (mZip.getEntryInfo(entry, &method, &uncompLen, &compLen, &offset, &modWhen, &crc32)) { LOGI("name:[%d] %s\n", i, name); LOGI("method: %d\n", method); LOGI("uncompLen: %d,\tcompLen: %d\n", uncompLen, compLen); LOGI("offset: %lld,\tcrc32: 0x%lx\n", offset, crc32); } } } return 0;}int testIsInZip(int argc, char** argv){if (argc < 2) {LOGE("parameter is error! :%s filepath", argv[0]);return -1;}return is_in_zip(argv[1]);}int testRead(int argc, char** argv){int zfd = 0;char buf[100] = {0};if (argc < 2) {LOGE("parameter is error! :%s filepath", argv[0]);return -1;}zfd = zip_open(argv[1]);LOGI("zfd = 0x%x", zfd);if (ZIP_IS_VALID(zfd)) {zip_read(zfd, buf, 10);LOGI("read: %s", buf);memset(buf, 0, sizeof(buf));zip_seek(zfd, 5, SEEK_SET);zip_read(zfd, buf, 10);LOGI("read: %s", buf);zip_close(zfd);}return 0;}int testStat(int argc, char** argv){struct stat buf;if (argc < 2) {LOGE("parameter is error! :%s filepath", argv[0]);return -1;}zip_stat(argv[1], &buf);return 0;}int main(int argc, char** argv){ //testReadEntry(argc, argv);//testIsInZip(argc, argv);//testRead(argc, argv);testStat(argc, argv); return 0;}
Android. mk
LOCAL_PATH:= $(call my-dir)#################################include $(CLEAR_VARS)LOCAL_SRC_FILES:= \zip_wrapper.cppLOCAL_CFLAGS := LOCAL_SHARED_LIBRARIES := libutils LOCAL_C_INCLUDES := .LOCAL_MODULE_TAGS:= optionalLOCAL_MODULE:= libreadzipinclude $(BUILD_STATIC_LIBRARY)#################################include $(CLEAR_VARS)LOCAL_SRC_FILES:= \zip_main.cpp LOCAL_CFLAGS := LOCAL_STATIC_LIBRARIES := libreadzipLOCAL_SHARED_LIBRARIES := libutils LOCAL_C_INCLUDES := .LOCAL_MODULE_TAGS:= optionalLOCAL_MODULE:= readzipinclude $(BUILD_EXECUTABLE)