服务器之家:专注于VPS、云服务器配置技术及软件下载分享
分类导航

PHP教程|ASP.NET教程|Java教程|ASP教程|编程技术|正则表达式|C/C++|IOS|C#|Swift|Android|VB|R语言|JavaScript|易语言|vb.net|

服务器之家 - 编程语言 - C# - unity 如何使用文件流读取streamingassets下的资源

unity 如何使用文件流读取streamingassets下的资源

2022-11-13 12:19此车先开 C#

这篇文章主要介绍了unity 使用文件流读取streamingassets下的资源操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧

目的:读取streamingassets下的文件中指定的一段字节

已知:文件中的起始位置,和需要读取的长度

1.android下读取

1.1 不能直接使用C#的FileStream,读取失败

?
1
2
3
var buffer = new byte[size];
FileStream stream = File.OpenRead(path);
stream.Read(buffer , pos, size);

报错:

IsolatedStorageException: Could not find a part of the path "/jar:file:/data/app/com.xxx.xxxx-1/base.apk!/assets/xxx.pack".

1.2 可以使用Unity原生接口与Android交互

主要过程:

Java

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
public class XXXPlugin extends UnityPlayerNativeActivity {
    protected AssetManager assetManager;
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        assetManager = getAssets();
    }
 
    //返回字节数组
    public byte[] LoadBytes(String path,int offset,int len)
    {
         //可以缓存起来,不需每次都open
         InputStream inputStream = assetManager.open(path);
         try {
                 byte buf[] = new byte[len];
                 inputStream.reset();
                 
                //注意skip、read的可靠性
                 inputStream.skip(offset);
                 inputStream.read(buf,0,len)
 
                 inputStream.close();
                 return buf;
    
            }
        catch (IOException e) {
                Log.v ("unity", e.getMessage());
        }
        return null;
    }
 
}

注意skip、read的可靠性,每次调用不一定能返回正确长度,可能需多次调用。

参考how-does-the-skip-method-in-inputstream-work

C#:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
public static byte[] read_streamingpath_bytes(string path,IntPtr ptr, int pos, int size)
{
    using (AndroidJavaClass cls = new AndroidJavaClass("com.XXX.XXXPlugin";) )
    {
       AndroidJavaObject  m_AndroidJavaObject = cls.GetStatic<AndroidJavaObject>("mainActivity");
 
        byte[] s = m_AndroidJavaObject.Call<byte[]>("LoadBytes", path, pos, size);
 
        return s;
    }
    return null;
}

这种方法是在Java分配内存。

1.3 更灵活的方法,使用JNI,可以从C#传递指针到C++

在Android Studio中生成库libNativeLib.so文件,参考NativeReadBytes

C++

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
#include "com_XXX_NativeHelper.h"
#include <android/asset_manager_jni.h>
#include <android/asset_manager.h>
#include <string>
#include <jni.h>
#include <stdint.h>
 
#ifdef __cplusplus
extern "C" {
#endif
 
static AAssetManager *assetManager = nullptr;
 
JNIEXPORT void JNICALL Java_com_XXX_NativeHelper_SetAssetManager
        (JNIEnv *env, jobject jobj, jobject jassetManager) {
    assetManager = AAssetManager_fromJava(env, jassetManager);
}
 
JNIEXPORT int32_t JNICALL ReadAssetsBytesWithOffset(uint32_t pathKey, char* fileName, unsigned char** result, int32_t offset, int32_t length){
    if(assetManager == nullptr){
        return -1;
    }
    AAsset* asset = asset = AAssetManager_open(assetManager, fileName, AASSET_MODE_UNKNOWN);
    if(asset == nullptr){
        return -1;
    }
    off_t size = AAsset_getLength(asset);
    if(size > 0){
        try {
            AAsset_seek(asset, offset, SEEK_SET);
            AAsset_read(asset, *result, length);
        }catch (std::bad_alloc){
            *result = nullptr;
            return -1;
        }
    }
    AAsset_close(asset);
    return (int32_t)length;
}
#ifdef __cplusplus
}
#endif

Java

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
//XXXPlugin.java
public class XXXPlugin extends UnityPlayerNativeActivity {
    static{
        System.loadLibrary("NativeLib");
    }
 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  mainActivity = this;
  
  
        //设置AssetManager, C++中要使用
  NativeHelper.SetAssetManager(getAssets());
   }
 
}
 
//NativeHelper.java
public class NativeHelper {
    public static native void SetAssetManager(AssetManager assetManager);
}

C#

?
1
2
3
4
5
6
7
8
public class ReadNativeByte
    {
 
#if UNITY_ANDROID
        [DllImport("NativeLib")]
        public static extern int ReadAssetsBytesWithOffset(uint pathKey,string name, ref IntPtr ptr, int offset, int length);
#endif
    }

2.IOS下读取

可以直接在C#下读取,StreamAsseting只有读的权限,用OpenRead

?
1
2
3
4
byte[] bytes = new byte[len];
FileStream stream = File.OpenRead(path);
stream.Seek(offset, SeekOrigin.Begin);
stream.Read(bytes, 0, len);

补充:unity中 在移动平台各种读写文件夹存路径整理 如 StreamingAssets 等文件夹 各个路径在各种平台的文件路径

1:Resources 文件夹 少用

unity 如何使用文件流读取streamingassets下的资源

?
1
2
3
4
5
6
//资源卸载
    /*
     *  Resources.UnloadAsset(obj):卸载非 GameObject类型的资源,会将内存中已加载资源及其克隆体卸载。
        Destroy(obj):仅用于卸载GameObject类型的资源的克隆体。
        DestroyImmediately(obj):卸载GameObject类型的资源,会将内存中已加载资源及其克隆体卸载,但该方法只能用在非编辑模式下,否则会报错提示改为DestroyImmediately(obj, true),然而编辑模式下使用该函数会连文件夹里的原始Asset一并删除。
     */

2:StreamingAssets

在移动端也是只可读的不能写入数据 主要用来存放二进制文件。

?
1
2
3
4
5
6
7
8
//安卓下这两个文件夹路径相同
   //Application.streamingAssetsPath = jar:file:///data/app/com.xxx.xxx-1.apk!/assets/  == "jar:file://"+Application.dataPath+"!assets/"
   //Application.dataPath+"!assets/" = /data/app/com.xxx.xxx-1.apk!assets/
   //Ios下
   //Application.dataPath + "/Raw/" == @"file:///" + Application.streamingAssetsPath + "/"
   //Editor WIN
   //@"file:///" + Application.streamingAssetsPath + "/"
   //"file:///" + Application.dataPath + "/StreamingAssets" + "/"
?
1
2
3
4
5
6
7
8
9
10
11
12
13
private string path = string.Empty;
    public string GetSAPath()
    {
        //安卓平台 加文件名
#if UNITY_ANDROID && !UNITY_EDITOR
        path =  Application.streamingAssetsPath + "/"
#elif UNITY_IPHONE && !UNITY_EDITOR
        path = @"file:///" + Application.streamingAssetsPath + "/";
#elif UNITY_STANDLONE_WIN||UNITY_EDITOR
       path =  @"file:///" + Application.streamingAssetsPath + "/";
#endif
        return path;
    }

3:Application.persistentDataPath

这个目录可读可写 一般存本地关卡等

用于存档 直接使用 打包之前是没有这个目录的,直到应用程序在手机上安装完毕才有这个目录。

该文件存在手机沙盒中,因为不能直接存放文件,

1.通过服务器直接下载保存到该位置,也可以通过Md5码比对下载更新新的资源

2.没有服务器的,只有间接通过文件流的方式从本地读取并写入Application.persistentDataPath文件下,然后再通过

Application.persistentDataPath来读取操作。

注:在Pc/Mac电脑 以及Android跟Ipad、ipone都可对文件进行任意操作,另外在IOS上该目录下的东西可以被iCloud自动备份。

?
1
Application.persistentDataPath + "/tempDic", "testXml"

对应存储路径

Windows应用商店应用程序:

?
1
2
3
application.persistentdatapath指向%userprofile%\appdata\local\packages\<productName>\localstate
 
ios:application.persistentdatapath指向/var/mobile/containers/data/application/<guid>/documents

android:application.persistentdatapath指向大多数设备上的/storage/emulated/0/android/data/<packagename>/文件(有些旧手机可能指向SD卡上的位置,如果存在),该路径使用android.content.context.getexternalfilesdir解析

4:Application.temporaryCachePath

来操作文件 同上但是 此属性用于返回一个临时数据的缓存目录(不会备份并且清空缓存会清掉)

以上为个人经验,希望能给大家一个参考,也希望大家多多支持服务器之家。如有错误或未考虑完全的地方,望不吝赐教。

原文链接:https://blog.csdn.net/hjflyblue/article/details/90115739

延伸 · 阅读

精彩推荐
  • C#C# 对Outlook2010进行二次开发的图文教程

    C# 对Outlook2010进行二次开发的图文教程

    下面小编就为大家分享一篇C# 对Outlook2010进行二次开发的图文教程,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...

    久久小垠5662022-02-16
  • C#c#实现输出的字符靠右对齐的示例

    c#实现输出的字符靠右对齐的示例

    下面小编就为大家分享一篇c#实现输出的字符靠右对齐的示例,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...

    杨明波(Leo Yang)4122022-02-15
  • C#C# 获取当前年份的周期及周期所在日期范围(推荐)

    C# 获取当前年份的周期及周期所在日期范围(推荐)

    这篇文章主要介绍了C# 获取当前年份的周期,周期所在日期范围 ,非常不错,具有一定的参考借鉴价值,需要的朋友可以参考下...

    有创软件工作室5662022-02-23
  • C#轻松学习C#的String类

    轻松学习C#的String类

    轻松学习C#的String类,小编也是第一次接触C#的String类,感兴趣的小伙伴们可以参考一下,大家一起学习。...

    丿木呈广予口贝10722021-11-03
  • C#C#时间操作类分享

    C#时间操作类分享

    这篇文章主要为大家分享了C#时间操作类,秒转换成分钟,获得两个日期的间隔等,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...

    孤者自清6672022-01-11
  • C#C#实现两个窗体之间数值传送的方法

    C#实现两个窗体之间数值传送的方法

    这篇文章主要介绍了C#实现两个窗体之间数值传送的方法,涉及C#中WinForm窗体数值传递的相关技巧,具有一定参考借鉴价值,需要的朋友可以参考下...

    期待秋天的叶5302021-11-05
  • C#C#实现子窗体与父窗体通信方法实例总结

    C#实现子窗体与父窗体通信方法实例总结

    这篇文章主要介绍了C#实现子窗体与父窗体通信方法,实例总结了常用的四种窗体通信方法,具有一定参考借鉴价值,需要的朋友可以参考下...

    C#教程网8342021-10-26
  • C#C#创建自定义控件及添加自定义属性和事件使用实例详解

    C#创建自定义控件及添加自定义属性和事件使用实例详解

    这篇文章主要给大家介绍了关于C#创建自定义控件及添加自定义属性和事件使用的相关资料,文中通过示例代码介绍的非常详细,对大家学习或者使用C#具有...

    Im1smb8522022-09-07