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

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

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

1.android下读取

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

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

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#:


            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++

#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

//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#

 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

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

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

1:Resources 文件夹 少用

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

2:StreamingAssets

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

 //安卓下这两个文件夹路径相同
    //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" + "/"
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自动备份。

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

对应存储路径

Windows应用商店应用程序:

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

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

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

(0)

相关推荐

  • unity里获取text中文字宽度并截断省略的操作

    前言 在unity的ugui中Text控件,有时我们会有各种各样的需求,比如类似html中css的text-overflow属性,希望一段文字如果不够长就全显示,如果特别长就截断并且后面加上例如-这种后缀. 好吧这样的需求在ugui里貌似没有现成的方法,如果有的话麻烦指点一下~ 实现 大概的思路就是 - 首先要能判断什么时候overflow - 并且支持加上后缀 那么text控件本来是支持overflow然后直接截断的,但是比较暴力,直接砍断,不能加后缀,并不满足我们的需求. 然后如果简单的通过

  • Unity使用物理引擎实现多旋翼无人机的模拟飞行

    内容简介 最近在用Unity实现无人机的模拟飞行,但发现站里基本没有完整介绍如何实现该功能的博客,因时间紧迫,就自己简单做了一个仿真(不是完全按照现实物理情景来做,即通过各个螺旋桨旋转产生力带动机体飞行).下面我会简述完全按现实物理情景实现模拟飞行,并详细描述我自己做的模拟飞行(不完全仿真),给各位提供参考. 现实物理情景的实现--简述(以四旋翼无人机为例) 因为我没有实现1:1仿真,所以这里只介绍思路,希望能给到读者一点启发. 构建一个四旋翼无人机模型(可以网上下载.或用Maya等建一个) 将

  • unity avprovideo插件的使用详解

    1.新建一个MediaPlayer组件 2.在canvas下新建一个AVProVideo组件 并将上一步新建的MediaPlayer组件赋值到avprovideo组件上的mediaplayer上 3.将需要播放的视频放在StreamingAssets文件夹下 接下来就是用代码调用了 1._mediaPlayer.OpenVideoFromFile(MediaPlayer.FileLocation.RelativeToStreamingAssetsFolder, 视频路径, 是否自动播放);//加

  • unity 如何获取Text组件里text内容的长度

    我就废话不多说了,大家还是直接看代码吧~ /// <summary> /// 计算字符串在指定text控件中的长度 /// </summary> /// <param name="message"></param> /// <returns></returns> int CalculateLengthOfText(string message,Text tex) { int totalLength = 0; Fon

  • Unity3d 如何更改Button的背景色

    我就废话不多说了,大家还是直接看代码吧~ using UnityEngine; using System.Collections; public class ButtonStyle : MonoBehaviour { public Color _color;//在编辑环境下选择背景色,透明度不能为0 public Texture2D tex; void OnGUI(){GUI.Button(new Rect(0,0,100,100),"tex");Color oldColor = GU

  • Unity解析gif动态图操作

    工作需求,要播放一张gif图片,又不想转成视频播放,就开始研究怎样解析gif,在网上也看了不少教程,最后根据自己需求写了个脚本. 首先,Unity是不支持gif的(至少我没找到方法),而又要在NGUI中显示gif图片.所以就想到了将gif解析成序列帧再去循环播放. 有人说可以找软件解析,然后导入Unity做动画,最终我没有采用,自己再Unity中以代码解析,然后播放的. 代码如下 (在Awake中解析的,因为要在其他脚本调用,实时解析的话,到时候会花费一会时间): using System.Co

  • unity 文件流读取图片与www读取图片的区别介绍

    IO流代码: void LoadByIO() { float time = Time.time; FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read); fs.Seek(0, SeekOrigin.Begin); byte[] bytes = new byte[fs.Length]; fs.Read(bytes, 0, (int)fs.Length); fs.Close(); fs.Dispose(); fs =

  • unity 如何获取button文本的内容

    如下就可以获取button中的文本内容 using System.Collections.Generic; using UnityEngine; using UnityEngine.UI; using System; public class ButtonContent : MonoBehaviour{ public Button btn; void Start(){ btn = GameObject.Find("填写button名").getComponent<Button&g

  • Unity3D 单例模式和静态类的使用详解

    Unity3D的API提供了很多的功能,但是很多流程还是会自己去封装一下去.当然现在网上也有很多的框架可以去下载使用,但是肯定不会比自己写的用起来顺手. 对于是否需要使用框架的问题上,本人是持肯定态度的,把一些常用方法进行封装,做成一个功能性的框架,可以很大程度上提高代码的效率,维护也方便. 对于网络上很多教程上使用的"游戏通用MVC框架",现在看来并不符合MVC这种结构性框架的设计思想:要知道,MVC最初是被设计为Web应用的框架,而游戏中的很多事件并不是通过用户点击UI发生的,Vi

  • Unity3D启动外部程序并传递参数的实现

    之前开发项目,一直都使用的是外壳程序加子程序的模式,通过外壳程序去启动子程序,外壳程序和子程序之间的通信,是使用配置文件完成的. 我总觉得这样通信很麻烦,因为外壳程序需要对配置文件进行更改和写入,然后子程序又要读取信息.而且整合的时候,会导致有很多配置文件,而且需要对路径做很多处理和限制. 我发现Process.Start()函数中,是可以传递参数的. 也就是说,我们是可以在使用Process.Start()函数启动外部程序时,传递参数的进行通信的. 具体操作如下: public void St

随机推荐