关于Android/IOS里边读取StreamingAsset目录 文件流

来源:互联网 发布:python的科学计数法 编辑:程序博客网 时间:2024/06/06 13:14

1.用Android接口来读取streamingAsset目录 可以提高效率,www方式效率不好 还耗内存。读取byte后直接CreateFromMemory 来创建bundle。其他模式还是CreateFromFile来创建效率更好,memory的方式耗内存,所以大文件还是要拷出来放在file目录 用 CreateFromFile来创建,IOS上全部用CreateFromFile。

public byte[] getFromAssetss(String fileName){ //android里边读取streamingAsset目录的文件

        try { 
        //得到资源中的Raw数据流  
            InputStream in = getResources().getAssets().open(fileName);   
          
            //得到数据的大小  
            int length = in.available();         
          
            byte [] buffer = new byte[length];          
          
            //读取数据  
            in.read(buffer);           
            //依test.txt的编码类型选择合适的编码,如果不调整会乱码   
           // res = EncodingUtils.getString(buffer, "BIG5");   
              
            //关闭      
            in.close();  
            return  buffer;
        
        } 
        catch (Exception e)
        { 
            e.printStackTrace(); 
            return null;
        }     

}


关于文件读取速度 1 最快的是File目录下的File.readallbytes   其次用上边的接口读取StreamingAssets 目录 最后是WWW方式异步读取StreamingAssets 目录。

-----------------------------------------------------------------------------

上边是读取整个byte文件

2.下边方法是读StreamingAssets 文件流方式,读取的是byte的部分数据,注意的是native和java的交互的引用计数不得超过512 也就是一瞬间同时请求return的数据不能太多 不然内存的自动释放 反应不过来。解决的方法是把该段数据请求堆栈设为局部引用。在Unity里边如下使用:

for (int i=0; i<5000; i++) {
AndroidJNI.PushLocalFrame (0);
byte[] data = CenterGhome.getStreamFromAssetss ("test.x", 0, a1.Length);
AndroidJNI.PopLocalFrame (System.IntPtr.Zero);
}

------------------

   // HashMap<String, InputStream> filemap = new HashMap<String, InputStream>();
   // byte [] buffer = new byte[5*1024*1024];;
public byte [] getStreamFromAssetss(String fileName, int offset,int length){ //Android里边  not pathName
        try {
        /* InputStream in=null;
        if(!filemap.containsKey(fileName))
        {
        in = getResources().getAssets().open(fileName);   
        filemap.put(fileName, in);
        in.mark(10*1024*1024);//设置标记方便reset恢复原始位置
        }
        else
        {
        in = filemap.get(fileName);
        }*/
       


        InputStream in = getResources().getAssets().open(fileName);   
            //得到数据的大小  
            if(in!=null)
            {                    
            // int length0 = in.available();       
            byte []  buffer = new byte[length]; //这里new 好像比去unity里边copy data 快 
           
            //  in.reset();//恢复原始位置
             in.skip(offset);
             int readCount = 0; // 已经成功读取的字节的个数
             while (readCount < length) 
             {
             readCount += in.read(buffer, readCount, length - readCount);//必须要慢慢读 不然可能读不完全。
             }
            in.close();
            in=null;
            return  buffer;//一帧内请求不得超过512次数  。unity里边调用要设置局部引用AndroidJNI.PushLocalFrame (0);AndroidJNI.PopLocalFrame (System.IntPtr.Zero);不然超过512就要报错。
            }
        } 
        catch (Exception e)
        { 
        Log.d("Unityjar","load Stream failed:" +fileName+e.getMessage());
            return null;
        }  
        
        return null;

-------------------------------------------IOS--------------------------------------------------------------

ios下边的目录可以使用FIle.Read 直接读取,但是StreamAsseting目录 文件流只能使用myStream = File.OpenRead(myPath); 来读。原因是FileMode.Open有读写权限 而StreamAsseting只有读的权限 所以 用FIle.Open会出错:Access to the path "/..Raw/4.page" is denied.

Note that on some platforms it is not possible to directly access the StreamingAssets folder because there is no file system access in the web platforms, and because it is compressed into the .apk file on Android. On those platforms, a url will be returned, which can be used using the WWW class.

---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

3.Native层通过JNI去读StreamingAsset资源:unity里边由于需要后台线程去加载资源,不能直接访问AndroidJni,然后就自己使用native层来读 使用.so库来加载:

dsnative.cpp

#include <jni.h>#include <sys/types.h>#include <stdlib.h>#include <android/asset_manager_jni.h>#include <android/asset_manager.h>#include <android/log.h>#include <stdio.h>#include <unistd.h>#include <dlfcn.h>#include <stdio.h>#include <fcntl.h>#define LOGD(...)  __android_log_print(ANDROID_LOG_DEBUG,"UnityNative",__VA_ARGS__) // 定义LOGD类型#define  LOGW(...)  __android_log_print(ANDROID_LOG_WARN,"UnityNative",__VA_ARGS__)extern "C" {float add(float x, float y)//test{//LOGD("aaaaaaaaaaaaaa");return x + y;}static AAssetManager* mgr=NULL;void  Java_com_meiyu_dungeonstriker_DSActivity_initreadFromAssets(JNIEnv* env,jclass tis,jobject assetManager){ LOGW("init_DSActivity_initreadFromAssets"); mgr = AAssetManager_fromJava(env, assetManager); if(mgr==NULL)   { LOGW(" %s","AAssetManager==NULL");      return ;   }}void getNativeStreamFromAssets(char* fileName,char* data, int offset,int length){ if(mgr==NULL) { LOGW("mgr is null "); return ; } AAsset* asset = AAssetManager_open(mgr, fileName,AASSET_MODE_UNKNOWN); if(asset==NULL) { LOGW("asset is null "); return ; } AAsset_seek(asset,offset,SEEK_SET); AAsset_read(asset, data, length); AAsset_close(asset);}JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *jvm, void *reserved){LOGW("JNI_OnLoad");JNIEnv* env = NULL;#ifdef __cplusplusif (jvm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK)#elseif ((*jvm)->GetEnv(jvm,(void**) &env, JNI_VERSION_1_4) != JNI_OK)#endif    {        return -1;    }#ifdef __cplusplusjclass DSActivity = env->FindClass("com/meiyu/dungeonstriker/DSActivity");#elsejclass DSActivity = (*env)->FindClass(env,"com/meiyu/dungeonstriker/DSActivity");#endif    if(DSActivity != NULL)    {#ifdef __cplusplus    jmethodID getSDPath = env->GetStaticMethodID( DSActivity, "getSDPath","()Ljava/lang/String;");#else    jmethodID getSDPath = (*env)->GetStaticMethodID(env, DSActivity, "getSDPath","()Ljava/lang/String;");#endif    jstring jstr = NULL;#ifdef __cplusplus    jstr = (jstring)env->CallStaticObjectMethod(DSActivity, getSDPath);#else    jstr = (jstring)(*env)->CallStaticObjectMethod(env, DSActivity, getSDPath);#endif    const char* cstr = NULL;#ifdef __cplusplus    cstr = env->GetStringUTFChars(jstr, 0);#else    cstr = (*env)->GetStringUTFChars(env,jstr, 0);#endif    if(cstr==NULL)    {    LOGW("11getSDPath=NULL");    }    else    {    //LOGW("g_ResPath=%s",g_ResPath);    //LOGW("cstr=%s",cstr);    LOGW("11getSDPath OK");    }    //strcpy(g_ResPath,cstr);///#ifdef __cplusplus    env->ReleaseStringUTFChars(jstr,cstr);#else    (*env)->ReleaseStringUTFChars(env,jstr, cstr);#endif    //LOGW(cstr);    //__android_log_print(ANDROID_LOG_WARN,"Unity",(const char*)cstr);    }    return JNI_VERSION_1_4;}JNIEXPORT void JNICALL JNI_OnUnload(JavaVM *jvm, void *reserved){LOGW("JNI_OnUnload");return;}}

android.mk:

LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE    := dsnative
LOCAL_SRC_FILES := dsnative.cpp
LOCAL_SHARED_LIBRARIES += libandroid
LOCAL_LDLIBS += -llog -landroid -lEGL -lz
include $(BUILD_SHARED_LIBRARY)


application.mk
APP_ABI := armeabi armeabi-v7a x86
APP_STL:=stlport_static


java里边调用初始化接口:


public native void  initreadFromAssets(AssetManager ass);
// Setup activity layout
@Override protected void onCreate (Bundle savedInstanceState)
{

System.loadLibrary("dsnative");
initreadFromAssets(getAssets());
}
c#里边使用native接口:

[DllImport("dsnative")]
private static extern void getNativeStreamFromAssets(string filename,byte[] data, int offset,int length);


byte[] data=new byte[1024*1024];
getNativeStreamFromAssets("test.x",data, a1.Length,b1.Length);

0 0
原创粉丝点击