NDK—文件拆分和合并

上一節(jié)我們學(xué)習(xí)的是JNI的調(diào)用,從最基本的配置到獨(dú)立去寫(xiě)一個(gè)JNI的過(guò)程,這里我們進(jìn)入NDK的學(xué)習(xí),在這篇文章我們從文件的拆分和合并兩個(gè)方面來(lái)進(jìn)行學(xué)習(xí)NDK的知識(shí)

  • NDK:Native Development 是一系列工具的集合,它提供了一系列的工具,幫助開(kāi)發(fā)者快速開(kāi)發(fā)C/C++的動(dòng)態(tài)庫(kù),并能自動(dòng)將so和java一起打包成apk

  • JNI:Java Native Interface 是java語(yǔ)言提供的java和C/C++相互溝通的機(jī)制,Java可以通過(guò)JNI調(diào)用C/C++代碼,C/C++的代碼也可以調(diào)用java代碼

  • 使用NDK開(kāi)發(fā)有以下的有點(diǎn)

    1. 項(xiàng)目需要調(diào)用底層的一些C/C++的一些東西,或者已經(jīng)在C/C++環(huán)境下實(shí)現(xiàn)了功能代碼,直接使用即可。NDK開(kāi)發(fā)常用于驅(qū)動(dòng)開(kāi)發(fā)、熱點(diǎn)共享、數(shù)學(xué)運(yùn)算、實(shí)時(shí)渲染游戲、音視頻處理、文件壓縮、人臉識(shí)別、圖片處理
    2. 為了效率更加的高效,將要求高性能的應(yīng)用邏輯使用C/C++開(kāi)發(fā),從而提高應(yīng)用程序的執(zhí)行效率,但是C/C++代碼雖然是高效的,在java與C/C++相互調(diào)用時(shí)卻增加了開(kāi)銷(xiāo)
    3. 基于安全性的考慮,防止代碼被反編譯,為了安全起見(jiàn),使用C/C++語(yǔ)言來(lái)編寫(xiě)重要的部分以增加系統(tǒng)的安全性,最后生成so庫(kù),便于給人提供方便。
    4. 便于移植,用C/C++寫(xiě)的庫(kù)可以方便在其他的嵌入式平臺(tái)上再次使用,例如在IOS也可以使用Android的so文件

正文

NDK配置

下載NDK的包并將Eclipse中的配置NDK的相關(guān)的路徑,接下來(lái)按照上篇中講解的JNI的那樣,先寫(xiě)一個(gè)native方法并使用javah生成.h文件

然后添加native支持


在這里我們使用的是C語(yǔ)言,所以在Android.mk中LOCAL_SRC_FILES使用的是.c,jni目錄下也是.c文件

我們先來(lái)看一下Android.mk文件的內(nèi)容

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE    := ndk_file_patch
LOCAL_SRC_FILES := ndk_file_patch.c
LOCAL_LDLIBS:= -llog
include $(BUILD_SHARED_LIBRARY)

tips:

  1. LOCAL_PATH := $(call my-dir) 設(shè)置當(dāng)前的編譯目錄
  2. include $(CLEAR_VARS) 清除LOCAL_XX變量(LOCAL_PATH除外)
  3. LOCAL_MODULE指定當(dāng)前編譯模塊的名稱(chēng)
  4. LOCAL_SRC_FILES指代相應(yīng)的.c文件
  5. LOCAL_LDLIBS:= -llog代表著能夠在c中打印AndroidLog
  6. include $(BUILD_SHARED_LIBRARY) 動(dòng)態(tài)庫(kù);BUILD_STATIC_LIBRARY:靜態(tài)庫(kù), BUILD_EXECUTEABLE指:可執(zhí)行文件

當(dāng)將生成的.h文件放到j(luò)ni目錄下會(huì)看到j(luò)ni.h會(huì)找不到,這時(shí)候需要配置一下路徑


這樣我們就把NDK的環(huán)境配置就弄好了,我們build project就會(huì)在lib的下面生成相應(yīng)的so文件

以上是EclipseNDK的配置,AndroidStudio的配置類(lèi)似


在這里配置上NDK的路徑,然后在extend tool里面配置javah和ndk build


就像這樣,接下來(lái)的工作就和在Eclipse里面的操作一樣了

文件的拆分

首先我們?cè)赾中開(kāi)發(fā)時(shí)打印AndroidLog需要引入相應(yīng)的.h

#include <android/log.h>

具體的代碼

__android_log_print(ANDROID_LOG_WARN,"lypop","This file_num is:%d",file_num);

相應(yīng)的拆分步驟:

  1. 獲取到相應(yīng)的分割文件的路徑,也就是講jstring轉(zhuǎn)化為char*

     const char* path = (*env)->GetStringUTFChars(env,path_jstr,JNI_FALSE);
     const char* path_pattern = (*env)->GetStringUTFChars(env,path_pattern_jstr,NULL);
    
  2. 得到分割之后子文件的路徑列表信息(這里使用了二級(jí)指針來(lái)存儲(chǔ))

     char **patches = malloc(sizeof(char*)*file_num);
     int i = 0;
     for(; i <file_num; i++){
         patches[i] = malloc(sizeof(char) * 100);
         //元素進(jìn)行賦值
         sprintf(patches[i],path_pattern,(i+1));
         __android_log_print(ANDROID_LOG_WARN,"lypop","patches[%d]:%s",i,patches[i]);
     }
    
  3. 得到文件的大小并計(jì)算每個(gè)部分的大小

     long getFileSize(char *path){
         FILE *fp = fopen(path,"rb");
         fseek(fp,0,SEEK_END);
         return ftell(fp);
     }
    
     int fileSize = getFileSize(path);
     FILE *fpr = fopen(path,"rb");
    
     int part = fileSize / file_num;
    
  4. 開(kāi)始對(duì)每個(gè)文件進(jìn)行寫(xiě)入

     for(; i < file_num; i++){
     FILE *fpw = fopen(patches[i],"wb");
     int j = 0;
     for(; j < part; j++){
         //邊讀邊寫(xiě)
         fputc(fgetc(fpr),fpw);
     }
     if(i == (file_num - 1)){
         j = 0;
         for(; j < (fileSize % file_num); j++){
             //邊讀邊寫(xiě)
             fputc(fgetc(fpr),fpw);
         }
     }
     fclose(fpw);
     }
     fclose(fpr);
    

注意的是這里在最后的時(shí)候判斷是否寫(xiě)到最后一個(gè)文件,當(dāng)前如果是最后一個(gè)文件則最后將多出來(lái)的字節(jié)寫(xiě)入到最后一個(gè)文件中

  1. 釋放相應(yīng)的指針資源

     i = 0;
     for(; i < file_num; i++){
         free(patches[i]);
     }
     free(patches);
    
     (*env)->ReleaseStringUTFChars(env,path_jstr,path);
     (*env)->ReleaseStringUTFChars(env,path_pattern_jstr,path_pattern);
    

這樣就實(shí)現(xiàn)了對(duì)一個(gè)文件的拆分成若干個(gè)文件

文件的合并

文件的拆分和文件的合并過(guò)程是向逆的,核心代碼

    for(; i < file_num; i++){
    //每個(gè)子文件的大小
    int fileSize = getFileSize(patches[i]);
    FILE *fpr = fopen(patches[i],"rb");
    int j = 0;
    for(; j < fileSize; j++){
        fputc(fgetc(fpr),fpw);
    }
    fclose(fpr);
    }
    fclose(fpw);

以上就是NDK的簡(jiǎn)單使用,自己也是新手,希望對(duì)你有所幫助。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀(guān)點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容