Android NDKでZIP書庫内の画像ファイルを解凍する
今回はAndroid NDKにより、ZIP書庫内に含まれる画像ファイルを解凍するためのクラスを作成する。ZIP書庫の操作には「Android NDKの標準ライブラリにlibunzipを追加して利用する」で用意したlibunzipを利用する。
まずは雛形となるプロジェクトをEasyProjectGenerator for Androidで作る。C++、HelloJNIでSTLを有効にした。
自動生成されたプロジェクトをEclipseに取り込み、「ZipedImages.h」ファイルを新規作成してZIP書庫操作用のクラスを実装する。
#ifndef _ZIPEDIMAGES_H #define _ZIPEDIMAGES_H #include<string> #include<vector> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <android/log.h> #include "unzip.h" #define MAX_PATH 256 #define bool unsigned int #define true (1) #define false (0) class CZipedImages { protected: unzFile _zipFile; std::vector<unz_file_pos> _vFilePos; public: CZipedImages() { _zipFile = 0; __android_log_write(ANDROID_LOG_DEBUG,TAG,"CZipedImages::CZipedImages()"); } ~CZipedImages() { Close(); __android_log_write(ANDROID_LOG_DEBUG,TAG,"CZipedImages::~CZipedImages()"); } bool IsOpen(void) { __android_log_write(ANDROID_LOG_DEBUG,TAG,"CZipedImages::IsOpen()"); return (_zipFile != 0) ? true : false; } bool OpenZipFile(const char* pszFile) { __android_log_write(ANDROID_LOG_DEBUG,TAG,"CZipedImages::OpenZipFile()"); if(IsOpen() == true) return false; int nRet; _zipFile = unzOpen(pszFile); nRet = unzGoToFirstFile(_zipFile); while(nRet == UNZ_OK) { char pszFileName[MAX_PATH]; unz_file_info info; unz_file_pos pos; std::string strFile; std::string strExt; unzGetCurrentFileInfo(_zipFile,&info,pszFileName,MAX_PATH,NULL,0,NULL,0); strFile = pszFileName; strExt = strFile.substr(strFile.length() - 4,4); //いい加減な方法で拡張子取得 if(strExt == ".JPG" || strExt == ".jpg" || strExt == ".PNG" || strExt == ".png") //いい加減な方法で拡張子チェック { unzGetFilePos(_zipFile,&pos); _vFilePos.push_back(pos); } else { //処理されないファイル/フォルダをログ出力 __android_log_print(ANDROID_LOG_INFO,TAG,"NOT process : (%s)",pszFileName); } nRet = unzGoToNextFile(_zipFile); } return true; } void Close(void) { __android_log_write(ANDROID_LOG_DEBUG,TAG,"CZipedImages::Close()"); if(_zipFile != 0) unzClose(_zipFile); _zipFile = 0; _vFilePos.clear(); } int GetCount(void) { __android_log_write(ANDROID_LOG_DEBUG,TAG,"CZipedImages::GetCount()"); return _vFilePos.size(); } bool Extract(int nIndex,const char* pszFolder,std::string* pstrFile) { __android_log_write(ANDROID_LOG_DEBUG,TAG,"CZipedImages::Extract()"); if(IsOpen() == false) return false; if(nIndex > _vFilePos.size() || nIndex < 0) return false; int nRet; char pszFileName[MAX_PATH]; unz_file_info info; nRet = unzGoToFilePos(_zipFile,&_vFilePos[nIndex]); if(nRet != UNZ_OK) return false; nRet = unzGetCurrentFileInfo(_zipFile,&info,pszFileName,MAX_PATH,NULL,0,NULL,0); if(nRet != UNZ_OK) return false; __android_log_print(ANDROID_LOG_DEBUG,TAG,"CZipedImages::Extract() in process %s",pszFileName); std::string strPath; //保存先ファイルパス作成 { strPath = pszFolder; if(strPath.substr(strPath.length() - 1,1) != "/") strPath += "/"; if(pstrFile != NULL && *pstrFile != "") { if((*pstrFile)[0] != '/') strPath += *pstrFile; else strPath += pstrFile->substr(1,pstrFile->length() - 1); } else { char pszBuff[256]; std::string strExt; strExt = pszFileName; strExt = strExt.substr(strExt.length() - 4,4).c_str(); //いい加減な方法で拡張子取得 sprintf(pszBuff,"%d%s",nIndex,strExt.c_str()); if(pstrFile) *pstrFile = pszBuff; strPath.append(pszBuff); } } __android_log_print(ANDROID_LOG_DEBUG,TAG,"CZipedImages::Extract() : save to %s",strPath.c_str()); //解凍 { FILE *fp; fp = fopen(strPath.c_str(),"w"); if(fp == NULL) return false; char szBuffer[32768]; int dwSizeRead; nRet = unzOpenCurrentFile(_zipFile); if(nRet == UNZ_OK) { while ((dwSizeRead = unzReadCurrentFile(_zipFile,szBuffer,sizeof(szBuffer))) > 0) { fwrite(szBuffer,1,dwSizeRead,fp); } unzCloseCurrentFile(_zipFile); } fclose(fp); } return true; } }; #endif

#if(true) #define LOCAL_LOG #define LOCAL_LOGD #endif #include <string.h> #include <jni.h> #ifdef LOCAL_LOG #include <android/log.h> #endif #define TAG "Test122" #include "ZipedImages.h" extern "C" jstring Java_com_Test122_Test122Act_stringFromJNI(JNIEnv* env,jobject thiz) { CZipedImages cZip; cZip.OpenZipFile("/sdcard/desire_img.zip"); bool ret; int nSize; std::string strFile; nSize = cZip.GetCount(); //最初のファイルを解凍 strFile = ""; ret = cZip.Extract(0,"/sdcard",&strFile); if(ret) __android_log_print(ANDROID_LOG_DEBUG,"Test122","save to %s",strFile.c_str()); //5番目のファイルを解凍 strFile = ""; ret = cZip.Extract(5,"/sdcard",&strFile); if(ret) __android_log_print(ANDROID_LOG_DEBUG,"Test122","save to %s",strFile.c_str()); cZip.Close(); return env->NewStringUTF("Test122text"); }

LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE := Test122 LOCAL_SRC_FILES := Test122.cpp LOCAL_LDLIBS += -lz -lunzip LOCAL_IS_SUPPORT_LOG := true ifeq ($(LOCAL_IS_SUPPORT_LOG),true) LOCAL_LDLIBS += -llog endif include $(BUILD_SHARED_LIBRARY)
これで実行するとSDカード上のZIP書庫を読み込み、その中にあるファイルのうち2つが解凍された。
プロジェクトファイルをダウンロード