美文网首页Android高级技术Android开发经验谈Android开发
Android NDK开发之旅16--NDK--文件拆分与合并

Android NDK开发之旅16--NDK--文件拆分与合并

作者: 香沙小熊 | 来源:发表于2017-11-13 15:42 被阅读231次

    Android NDK开发之旅 目录

    1.JNI声明文件

    package com.haocai.ndktest;
    
    /**
     * Created by Xionghu on 2017/11/9.
     * Desc:
     */
    
    public class NDKFileUtils {
    
        /**
         * 拆分
         * @param path 完整包路径
         * @param path_pattern 分包路径
         * @param count
         */
        public native static void diff(String path,String path_pattern,int count);
    
    
        /**
         * 合并
         * @param path_pattern 分包路径
         * @param count
         * @param merge_path 完整包路径
         */
        public native static void patch(String path_pattern,int count,String merge_path);
    
        static {
            System.loadLibrary("mylibrary");
        }
    
    }
    

    2.javah生成的头文件

    怎样生成头文件请参考超级简单的Android Studio jni 实现(无需命令行)

    注意:新版Android Studio ndk-build 要指定Application.mk和Android.mk路径



    /* DO NOT EDIT THIS FILE - it is machine generated */
    #include <jni.h>
    /* Header for class com_haocai_ndktest_NDKFileUtils */
    
    #ifndef _Included_com_haocai_ndktest_NDKFileUtils
    #define _Included_com_haocai_ndktest_NDKFileUtils
    #ifdef __cplusplus
    extern "C" {
    #endif
    /*
     * Class:     com_haocai_ndktest_NDKFileUtils
     * Method:    diff
     * Signature: (Ljava/lang/String;I)V
     */
    JNIEXPORT void JNICALL Java_com_haocai_ndktest_NDKFileUtils_diff
      (JNIEnv *, jclass, jstring ,jstring, jint);
    
    /*
     * Class:     com_haocai_ndktest_NDKFileUtils
     * Method:    patch
     * Signature: (Ljava/lang/String;I)V
     */
    JNIEXPORT void JNICALL Java_com_haocai_ndktest_NDKFileUtils_patch
      (JNIEnv *, jclass, jstring, jint, jstring);
    
    #ifdef __cplusplus
    }
    #endif
    #endif
    
    

    3.根据生成的头文件写C程序

    #include "com_haocai_ndktest_NDKFileUtils.h"
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <android/log.h>
    
    #define LOGI(FORMAT,...) __android_log_print(ANDROID_LOG_INFO,"kpioneer",FORMAT,__VA_ARGS__)
    #define LOGE(FORMAT,...) __android_log_print(ANDROID_LOG_ERROR,"kpioneer",FORMAT,__VA_ARGS__)
    
    //获取文件大小
    long get_file_size( char *path){
         FILE *fp = fopen(path,"rb");
         fseek(fp,0,SEEK_END);
         return ftell(fp);
    
    }
    
    JNIEXPORT void JNICALL Java_com_haocai_ndktest_NDKFileUtils_diff
    (JNIEnv * env, jclass jcls, jstring path_jstr, jstring path_pattern_jstr, jint file_num) {
        //jstring -> char*
        //需要分割的文件路径
        const char* path = (*env)->GetStringUTFChars(env, path_jstr, NULL);
        const char* path_pattern = (*env)->GetStringUTFChars(env, path_pattern_jstr, NULL);
    
        //得到分割之后的子文件路径列表
        char **patches = malloc(sizeof(char*) * file_num);
    
        int i = 0;
        for (i = 0; i < file_num; i++) {
            patches[i] = malloc(sizeof(char) * 100);
            //元素复制
            //需要分割的文件:C://jason/
            sprintf(patches[i], path_pattern, (i + 1));
            LOGI("patch path:%s", patches[i]);
        }
    
        //不断读取path文件,循环写入file_num的文件
    
        //分割文件大小
        //整除
        //文件大小:90,分成9个文件,每个文件10
        //不整除
        //文件大小:110,分成9个文件
        //前(9-1)个文件为(110/(9-1))=13
        //最后一个文件(110%(9-1))=6
        long filesize = get_file_size((char*)path);
        FILE *fpr = fopen(path, "rb");
        //整除
        if (filesize % file_num == 0) {
            //单个文件大小
            int part = filesize / file_num;
            i = 0;
            //逐一写入不同的分割子文件
            for (; i < file_num; i++) {
                FILE *fpw = fopen(patches[i], "wb");
                int j = 0;
                for (; j < part; j++) {
                    //边读边写
                    fputc(fgetc(fpr), fpw);
                }
                fclose(fpw);
            }
        }
        else {
            //不整除
            int part = filesize / (file_num - 1);
            i = 0;
            //逐一写入不同的分割子文件
            for (; i < file_num - 1; i++) {
                FILE *fpw = fopen(patches[i], "wb");
                int j = 0;
                for (; j < part; j++) {
                    //边读边写
                    fputc(fgetc(fpr), fpw);
                }
                fclose(fpw);
            }
            //the last one
            FILE *fpw = fopen(patches[file_num - 1], "wb");
            i = 0;
            for (; i < filesize % (file_num - 1); i++) {
                fputc(fgetc(fpr), fpw);
            }
            fclose(fpw);
    
        }
        //关闭被分割的文件
        fclose(fpr);
    
        //释放
        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);
    
    }
    
    
    JNIEXPORT void JNICALL Java_com_haocai_ndktest_NDKFileUtils_patch
    (JNIEnv * env, jclass jcls, jstring path_pattern_jstr, jint file_num, jstring merge_path_jstr) {
    
        //合并之后的文件
        const char* merge_path = (*env)->GetStringUTFChars(env, merge_path_jstr, NULL);
        //子文件
        const char* path_pattern = (*env)->GetStringUTFChars(env, path_pattern_jstr, NULL);
    
        //得到分割之后的子文件路径列表
        char **patches = malloc(sizeof(char*) * file_num);
    
        int i = 0;
        for (i = 0; i < file_num; i++) {
            patches[i] = malloc(sizeof(char) * 100);
            //元素复制
            //需要分割的文件:C://jason/
            sprintf(patches[i], path_pattern, (i + 1));
            LOGI("patch path:%s", patches[i]);
        }
        FILE *fpw = fopen(merge_path, "wb");
        //把所有的分割文件读取一遍,写入一个总的文件中
        i = 0;
        for (; i < file_num; i++) {
            //每个字文件的大小
            long filesize = get_file_size(patches[i]);
            FILE *fpr = fopen(patches[i], "rb");
            int j = 0;
            for (; j < filesize; j++) {
                fputc(fgetc(fpr), fpw);
            }
            fclose(fpr);
    
        }
        fclose(fpw);
    
        //释放资源
        (*env)->ReleaseStringUTFChars(env, path_pattern_jstr, path_pattern);
        (*env)->ReleaseStringUTFChars(env, merge_path_jstr, merge_path);
    }
    
    

    4.写mk文件

    Android.mk

    LOCAL_PATH := $(call my-dir)
    
    include $(CLEAR_VARS)
    
    LOCAL_MODULE := mylibrary
    LOCAL_SRC_FILES =: mylibrary.c
    LOCAL_LDLIBS := -llog
    include $(BUILD_SHARED_LIBRARY)
    

    Applicatoin.mk

    APP_MODULES := mylibrary
    APP_ABI := armeabi-v7a armeabi arm64-v8a  #定义编译目标版本 ABI(应用二进制接口)  值为all时,代表所有版本
    APP_PLATFORM := android-14
    

    5.写Android调用库主程序

    package com.haocai.ndktest;
    
    import android.os.Bundle;
    import android.os.Environment;
    import android.support.v7.app.AppCompatActivity;
    import android.util.Log;
    import android.view.View;
    
    import java.io.File;
    
    public class MainActivity extends AppCompatActivity {
    
        private String SD_CARD_PATH;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            SD_CARD_PATH = Environment.getExternalStorageDirectory().getAbsolutePath();
        }
    
        /**
         * 拆分包
         *
         * @param v
         */
        public void diffPackage(View v) {
            String path = SD_CARD_PATH + File.separator+ "小苹果.mp3";
            String path_pattern = SD_CARD_PATH + File.separator +"小苹果_%d.mp3";
            NDKFileUtils.diff(path, path_pattern,3);
            Log.d("Main","拆分成功");
        }
    
        /**
         * 合并包
         *
         * @param v
         */
        public void patchPackage(View v) {
            String merge_path = SD_CARD_PATH + File.separator+ "小苹果_合并.mp3";
            String path_pattern = SD_CARD_PATH + File.separator +"小苹果_%d.mp3";
            NDKFileUtils.patch(path_pattern, 3,merge_path);
            Log.d("Main","合并成功");
        }
    }
    
    

    activity_main.xml

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        android:gravity="center_horizontal"
        tools:context="com.haocai.ndktest.MainActivity">
    
        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="拆分包"
            android:onClick="diffPackage"
            />
        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="合并包"
            android:onClick="patchPackage"
            />
    </LinearLayout>
    

    权限声明

        <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>
        <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
        <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
    

    6.运行结果

    1.要把小苹果.mp3文件放在Android手机sd目录下
    2.运行拆分包程序
    生成 小苹果_1.mp3 小苹果_2.mp3 小苹果_3.mp3
    3.运行合并包程序
    生成 小苹果_合并.mp3

    如下:

    11-13 15:17:01.076 2648-2648/com.haocai.ndktest I/kpioneer: patch path:/storage/emulated/0/小苹果_1.mp3
    11-13 15:17:01.076 2648-2648/com.haocai.ndktest I/kpioneer: patch path:/storage/emulated/0/小苹果_2.mp3
    11-13 15:17:01.076 2648-2648/com.haocai.ndktest I/kpioneer: patch path:/storage/emulated/0/小苹果_3.mp3
    11-13 15:17:02.016 2648-2648/com.haocai.ndktest D/Main: 拆分成功
    11-13 15:17:02.026 2648-2648/com.haocai.ndktest I/Choreographer: Skipped 56 frames!  The application may be doing too much work on its main thread.
    11-13 15:17:03.226 2648-2648/com.haocai.ndktest D/ViewRootImpl: ViewPostImeInputStage ACTION_DOWN
    11-13 15:17:03.286 2648-2648/com.haocai.ndktest I/kpioneer: patch path:/storage/emulated/0/小苹果_1.mp3
    11-13 15:17:03.286 2648-2648/com.haocai.ndktest I/kpioneer: patch path:/storage/emulated/0/小苹果_2.mp3
    11-13 15:17:03.286 2648-2648/com.haocai.ndktest I/kpioneer: patch path:/storage/emulated/0/小苹果_3.mp3
    11-13 15:17:04.256 2648-2648/com.haocai.ndktest D/Main: 合并成功
    
    先拆分后合并
    该项目源码下载

    特别感谢:
    动脑学院Jason







    微信号kpioneer

    相关文章

      网友评论

      本文标题:Android NDK开发之旅16--NDK--文件拆分与合并

      本文链接:https://www.haomeiwen.com/subject/dibamxtx.html