[Zip] using Android to directly read files in zip

Source: Internet
Author: User
Tags crc32

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)

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.