[zip]android下实现直接读取zip中的文件

1 篇文章 0 订阅

     不用解压,直接读取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);
	}

1.依赖于android framework中的ZipFileRO.h,要求在android系统源码环境中编译;

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);

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 __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_

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 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" {

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.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)




  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值