android常见问题之jni读取assets资源文件(附源码)

      assets目录底下的文件会被打包到一个apk文件里,这些资源在安装时他们并没被解压,使用时是直接从apk中读取的。这里介绍下怎么在jni内使用ndk自带api的接口函数读取assets资源文件,和libzip库函数的使用,可以用来读创建修改压缩文档,这里也是以读取apk安装包内的资源文件为例。


      1 用ndk自带的接口函数读apk包,从2.3开始提供这些接口函数,具体看头文件assert.h android/asset_manager.h android/asset_manager_jni.h,可以参考ndk自带例子中samples/native-audio/ jni/native-audio-jni.c。
/*******************************************************************************
* Function Name  : java_com_fontlose_ReadAssets_readFromAssets
* Description    : 定义:public native void  readFromAssets(AssetManager ass,String filename);
* Input          : AssetManager对象 filename资源名
* Output         : None
* Return         : None
*******************************************************************************/ 
void  Java_com_fontlose_ReadAssets_readFromAssets(JNIEnv* env,jclass tis,jobject assetManager,jstring filename)
{
   LOGI("ReadAssets"); 
   AAssetManager* mgr = AAssetManager_fromJava(env, assetManager);
   if(mgr==NULL)
   {
      LOGI(" %s","AAssetManager==NULL");
      return ;
   }
 
    /*获取文件名并打开*/
   jboolean iscopy;
   const char *mfile = (*env)->GetStringUTFChars(env, filename, &iscopy);
   AAsset* asset = AAssetManager_open(mgr, mfile,AASSET_MODE_UNKNOWN);
   (*env)->ReleaseStringUTFChars(env, filename, mfile);
   if(asset==NULL)
   {
      LOGI(" %s","asset==NULL");
      return ;
   }
   /*获取文件大小*/
   off_t bufferSize = AAsset_getLength(asset);
   LOGI("file size         : %d\n",bufferSize);
   char *buffer=(char *)malloc(bufferSize+1);
   buffer[bufferSize]=0;
   int numBytesRead = AAsset_read(asset, buffer, bufferSize);
   LOGI(": %s",buffer);
   free(buffer);
    /*关闭文件*/
   AAsset_close(asset);
}

在应用程序内使用定义和使用如下
public native void  readFromAssets(AssetManager ass,String filename);
readFromAssets(getAssets(),"log.txt");

logcat测试结果
12-15 15:27:33.290: INFO/ReadAssets(3570): ReadAssets
12-15 15:27:33.290: INFO/ReadAssets(3570): file size         : 138
12-15 15:27:33.290: INFO/ReadAssets(3570): : 。。。。。。。。。。。。。。。。
12-15 15:27:33.290: INFO/ReadAssets(3570): 这个例子从jni读取assets内文件
12-15 15:27:33.290: INFO/ReadAssets(3570): 。。。。。。。。。。。。。。。。



2 使用libzip库读apk包
     libzip 使用 C 库来 读创建修改压缩文档,关于libzip在andorid的移植可以参考老外做的android-ndk-assets.zip这个工程,已在NDK下可以编译了,修改下编译生成libzip.so,利用libzip.so和zip.h建立工程,使用libzip还可以读取apk包内其他压缩文件如AndroidManifest.xml布局xml等。
/*******************************************************************************
* Function Name  : java_com_fontlose_ReadAssets_readFromAssetsLibzip
* Description    : 定义:public native void  readFromAssetsLibzip(String apkpath,String filename);
* Input          : apkpath路径 filename 资源名
* Output         : None
* Return         : None
*******************************************************************************/ 
void  Java_com_fontlose_ReadAssets_readFromAssetsLibzip(JNIEnv* env,jclass tis,jstring assetpath,jstring filename)
{
   LOGI("ReadAssets"); 
  int i=0;
   jboolean iscopy;
   const char *mpath = (*env)->GetStringUTFChars(env, assetpath, &iscopy);
   struct zip* apkArchive=zip_open(mpath, 0, NULL);;
   (*env)->ReleaseStringUTFChars(env, filename, mpath);

   struct zip_stat fstat;
   zip_stat_init(&fstat);

   int numFiles = zip_get_num_files(apkArchive);
   LOGI("File numFiles %i \n",numFiles);
   for (i=0; i<numFiles; i++) {
     const char* name = zip_get_name(apkArchive, i, 0);
    
     if (name == NULL) {
      LOGE("Error reading zip file name at index %i : %s", zip_strerror(apkArchive));
      return;
    }
   
    zip_stat(apkArchive,name,0,&fstat);
    LOGI("File %i:%s Size1: %d Size2: %d", i,fstat.name,fstat.size ,fstat.comp_size)  ;
   }

   const char *fname = (*env)->GetStringUTFChars(env, filename, &iscopy);
   struct zip_file* file = zip_fopen(apkArchive, fname, 0);
 
   if (!file) {
     LOGE("Error opening %s from APK", fname);
     return;
    }

   zip_stat(apkArchive,fname,0,&fstat);
   (*env)->ReleaseStringUTFChars(env, filename, fname);
   char *buffer=(char *)malloc(fstat.size+1);
   buffer[fstat.size]=0;
   int numBytesRead =  zip_fread(file, buffer,fstat.size);;
   LOGI(": %s\n",buffer);
   free(buffer);
   zip_fclose(file);
   zip_close(apkArchive);
}


在应用程序内使用定义和使用如下

public native void  readFromAssetsLibzip(String apkpath,String filename);



readFromAssetsLibzip(getPackageResourcePath(),"assets/log.txt");


logcat测试结果

12-15 15:28:03.430: INFO/ReadAssets(3570): ReadAssets
12-15 15:28:03.440: INFO/ReadAssets(3570): File numFiles 14
12-15 15:28:03.440: INFO/ReadAssets(3570): File 0:assets/log 2.txt Size1: 138 Size2: 55
12-15 15:28:03.440: INFO/ReadAssets(3570): File 1:assets/log.txt Size1: 138 Size2: 55
12-15 15:28:03.440: INFO/ReadAssets(3570): File 2:res/layout/main.xml Size1: 956 Size2: 337
12-15 15:28:03.440: INFO/ReadAssets(3570): File 3:AndroidManifest.xml Size1: 1348 Size2: 531
12-15 15:28:03.440: INFO/ReadAssets(3570): File 4:resources.arsc Size1: 1480 Size2: 1480
12-15 15:28:03.440: INFO/ReadAssets(3570): File 5:res/drawable-hdpi/icon.png Size1: 3966 Size2: 3966
12-15 15:28:03.440: INFO/ReadAssets(3570): File 6:res/drawable-ldpi/icon.png Size1: 1537 Size2: 1537
12-15 15:28:03.440: INFO/ReadAssets(3570): File 7:res/drawable-mdpi/icon.png Size1: 2200 Size2: 2200
12-15 15:28:03.440: INFO/ReadAssets(3570): File 8:classes.dex Size1: 3468 Size2: 1680
12-15 15:28:03.440: INFO/ReadAssets(3570): File 9:lib/armeabi/libzip.so Size1: 217246 Size2: 46140
12-15 15:28:03.440: INFO/ReadAssets(3570): File 10:lib/armeabi/libreadres.so Size1: 3820 Size2: 1779
12-15 15:28:03.440: INFO/ReadAssets(3570): File 11:META-INF/MANIFEST.MF Size1: 852 Size2: 443
12-15 15:28:03.440: INFO/ReadAssets(3570): File 12:META-INF/CERT.SF Size1: 905 Size2: 487
12-15 15:28:03.440: INFO/ReadAssets(3570): File 13:META-INF/CERT.RSA Size1: 776 Size2: 606
12-15 15:28:03.440: INFO/ReadAssets(3570): : 。。。。。。。。。。。。。。。。
12-15 15:28:03.440: INFO/ReadAssets(3570): 这个例子从jni读取assets内文件
12-15 15:28:03.440: INFO/ReadAssets(3570): 。。。。。。。。。。。。。。。。

上面例子使用android.mk如下
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE    := readres
LOCAL_SRC_FILES := readres.c 
LOCAL_C_INCLUDES+= /opt/android-ndk-r5/platforms/android-9/arch-arm/usr/include
LOCAL_LDLIBS    += -L/opt/android-ndk-r5/platforms/android-9/arch-arm/usr/lib/ -llog
LOCAL_LDLIBS    += -landroid
LOCAL_LDLIBS    += -lz 
LOCAL_LDLIBS    += -L$(LOCAL_PATH) -lzip
include $(BUILD_SHARED_LIBRARY)


log.txt内容如下

。。。。。。。。。。。。。。。。
这个例子从jni读取assets内文件
。。。。。。。。。。。。。。。。


jni工程和测试工程源码我已上传到我的资源 有兴趣的童鞋可以下来看下

http://d.download.csdn.net/down/3518697/fontlose




  • 5
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
Android应用开发中,如果需要读取本地文件,可以通过JNI(Java Native Interface)来实现。 JNI是用于在Java代码与本地代码(C/C++)之间进行交互的一种技术。通过JNI,我们可以在Java代码中调用本地代码来访问系统底层源,例如读取本地文件。 以下是一种实现方式: 1. 创建一个Java类,用于加载本地库文件和声明本地方法。例如: ``` public class NativeFileReader { static { System.loadLibrary("native-library"); } public static native String readFile(String filePath); } ``` 2. 在本地代码中实现读取文件的方法,并将内容转换为字符串返回。例如: ``` #include <jni.h> #include <stdio.h> JNIEXPORT jstring JNICALL Java_com_example_NativeFileReader_readFile(JNIEnv* env, jclass clazz, jstring filePath) { const char* filePathStr = (*env)->GetStringUTFChars(env, filePath, NULL); FILE* file = fopen(filePathStr, "r"); if (file == NULL) { return NULL; } fseek(file, 0, SEEK_END); long fileSize = ftell(file); fseek(file, 0, SEEK_SET); char* buffer = malloc(fileSize + 1); fread(buffer, 1, fileSize, file); buffer[fileSize] = '\0'; fclose(file); (*env)->ReleaseStringUTFChars(env, filePath, filePathStr); jstring result = (*env)->NewStringUTF(env, buffer); free(buffer); return result; } ``` 3. 将本地代码编译为动态库文件,例如libnative-library.so。 4. 将生成的动态库文件放置到项目的jniLibs目录中。 5. 在Java代码中调用NativeFileReader类的readFile方法,传入要读取文件路径,就可以得到读取到的文件内容。例如: ``` String filePath = "/sdcard/example.txt"; String fileContent = NativeFileReader.readFile(filePath); ``` 这样,就能够通过JNI读取本地文件了。需要注意的是,为了保证文件读取的权限,需要在AndroidManifest.xml文件中添加文件读写权限的声明。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值