2014-08-27 15:55:02 lihandsome 阅读数 2906

Unity项目中需要读取一些二进制资源文件的时候,假设本项目资源是放在Assets/StreamingAssets/Data/文件夹下,这时候不同平台的读取方式是不一样的。直接贴码。


private static string RootPath
	{
		get{
			if(Application.platform == RuntimePlatform.IPhonePlayer)
			{
				return Application.dataPath +"/Raw/Data/";
			}
			else if(Application.platform == RuntimePlatform.Android)
			{
				return "jar:file://" + Application.dataPath + "!/assets/Data/"
			}
			else
			{
				return Application.dataPath + "/StreamingAssets/Data/";
			}
		}
	}


public static string ReadFile (string name)
	{
		string fileContent; 
		if(Application.platform == RuntimePlatform.Android)
		{
			WWW www = new WWW(RootPath + name);
			while(!www.isDone){};
			fileContent = www.text;
		}
		else
		{
			StreamReader sr = null;
			try{
				sr = File.OpenText(RootPath + name);
			}
			catch(Exception e){
				return null;
			}
			    
			while ((fileContent = sr.ReadLine()) != null) {
				break; 
			}
			sr.Close ();
			sr.Dispose ();
		}
		return fileContent;
	}

直接用资源名称作为参数,比如有个资源文件位置为:“Assets/StreamingAssets/Data/mydata.txt”,就可以ReadFile("mydata.txt")即可。

2014-02-18 10:37:55 chenluwolf 阅读数 1241

http://www.xuanyusong.com/archives/1069


     前几天有个朋友问我为什么在IOS平台中可以正常的读写文件可是在Android平台中就无法正常的读写。当时因为在上班所以我没时间来帮他解决,晚上回家后我就拿起安卓手机真机调试很快就定位问题所在,原来是他文件的路径写错了。开发中往往一道很难的问题解开的时候发现原来真的非常的简单,哇咔咔。  刚好在MOMO的书中也有涉及到文件的读取与写入,那么本节我将书中的部分内容搬到博客中为大家讲解一下。废话我就不多说了咱直奔主题,创建Text.cs脚本,直接挂在摄像机中。代码中包括:创建文件、读取文件、删除文件。

Text.cs

 

001 using UnityEngine;
002 using System.Collections;
003 using System.IO;
004 using System.Collections.Generic;
005 using System;
006  
007 public class Text : MonoBehaviour {
008     //文本中每行的内容
009     ArrayList infoall;
010     //皮肤资源,这里用于显示中文
011     public GUISkin skin;
012     void Start ()
013     {
014  
015         //删除文件
016         DeleteFile(Application.persistentDataPath,"FileName.txt");
017  
018         //创建文件,共写入3次数据
019         CreateFile(Application.persistentDataPath,"FileName.txt","宣雨松MOMO");
020         CreateFile(Application.persistentDataPath,"FileName.txt","宣雨松MOMO");
021         CreateFile(Application.persistentDataPath ,"FileName.txt","宣雨松MOMO");
022         //得到文本中每一行的内容
023         infoall = LoadFile(Application.persistentDataPath,"FileName.txt");
024  
025     }
026  
027    /**
028    * path:文件创建目录
029    * name:文件的名称
030    *  info:写入的内容
031    */
032    void CreateFile(string path,string name,string info)
033    {
034       //文件流信息
035       StreamWriter sw;
036       FileInfo t = new FileInfo(path+"//"+ name);
037       if(!t.Exists)
038       {
039         //如果此文件不存在则创建
040         sw = t.CreateText();
041       }
042       else
043       {
044         //如果此文件存在则打开
045         sw = t.AppendText();
046       }
047       //以行的形式写入信息
048       sw.WriteLine(info);
049       //关闭流
050       sw.Close();
051       //销毁流
052       sw.Dispose();
053    
054  
055   /**
056    * path:读取文件的路径
057    * name:读取文件的名称
058    */
059    ArrayList LoadFile(string path,string name)
060    {
061         //使用流的形式读取
062         StreamReader sr =null;
063         try{
064             sr = File.OpenText(path+"//"+ name);
065         }catch(Exception e)
066         {
067             //路径与名称未找到文件则直接返回空
068             return null;
069         }
070         string line;
071         ArrayList arrlist = new ArrayList();
072         while ((line = sr.ReadLine()) != null)
073         {
074             //一行一行的读取
075             //将每一行的内容存入数组链表容器中
076             arrlist.Add(line);
077         }
078         //关闭流
079         sr.Close();
080         //销毁流
081         sr.Dispose();
082         //将数组链表容器返回
083         return arrlist;
084    }  
085  
086   /**
087    * path:删除文件的路径
088    * name:删除文件的名称
089    */
090  
091    void DeleteFile(string path,string name)
092    {
093         File.Delete(path+"//"+ name);
094  
095    }
096  
097    void OnGUI()
098    {
099         //用新的皮肤资源,显示中文
100         GUI.skin = skin;
101         //读取文件中的所有内容
102         foreach(string str in infoall)
103         {
104             //绘制在屏幕当中,哇咔咔!
105             GUILayout.Label(str);
106         }
107  
108    }
109  
110 }

 

        代码中头文件需要注意一下,涉及到IO读取文件。创建文件、删除文件、读取文件的方法我也已经封装好,Start方法中为了避免上次保存文件的残留首先删除原来的文件,然后创建文件FileName.txt ,我们也可修改文件的类型的后缀名。这里我写的是.txt ,为了完整的让中文出现在IOS与Android中所以这里给文件中写的数据是”宣雨松MOMO”,最后在OnGUI中将读取文件的文本信息显示在屏幕中,脚本保存格式为UTF-16。

        代码中我们保存文件的路径是Application.persistentDataPath。 如果你写的路径是 Application.dataPath在编辑器中是可以正常读取,但是在IOS与Android中是无法读取的,昨天问我的那个朋友就是因为这里路径写的有问题没能成功的写入文件。 Application.persistentDataPath路径就是将文件保存在手机的沙盒中,如果在编辑器中运行本程序文件将保存在Finder-》 资源库-》Caches-》你的工程-》保存的文件 。本例的路径就是 Finder->资源库-> Caches -> txt->FileName.txt。

         OK 截至到这里,运行游戏后在编辑器中是可以正常的看到“宣雨松MOMO”出现在Game视图中,但是如果你编译在IOS或者Android上将只显示”MOMO”,原因很简单”宣雨松”三个字无法在Unity默认字体中找到,所以无法显示。而默认字体只有字母和数字、字符。我们为了在移动平台中正常的显示中文,需要自制中文字体包。下面我们开始制作一个简单的字体包,mac机的话大家可以在 资源库 -》 fonts中 找一个.ttf的字体,或者在网络中下载一个.ttf字体。MOMO比较喜欢微软雅黑字体,大家如果也喜欢微软雅黑可以在后面下载这个工程的源码,嘿嘿。如下图所示, Project视图中的”yh”就是MOMO在网络中下载的微软雅黑字体。

FontSize:字体的大小,这里我设置呈50,为了让大家在IPAD中能看的更清楚。

FontColor:字体颜色。

Character:这里选择Custom set,因为这里需要配置我们需要的字体。

CustomChars:这里输入需要制作的字体。Unity默认的字体包含数字符号字母,为了让移动设备支持中文,这里我输入”宣雨松”它将生成一个包含“宣雨松”的材质与贴图,也就是说将我们需要在移动设备中显示的任何字符串在这里配置一下就OK啦。

最后点击又小角的Apply按钮即可完成字体配置。

 

 

         将字符赋值给创建的皮肤文件然后应用在程序当中即可,如下图所示这是IPAD中截图的效果,大家应该会问上面代码中明明写入的是”宣雨松MOMO”为什么这里没能显示MOMO呢?蛤蛤 原因很简单,上图中在Custom Chars中我们只配置了 “宣雨松” 所以这里就只能显示”宣雨松”无法显示MOMO啦。。大家可根据自己需要显示的字符串添加进去即可。在程序中我们可能会写入很多的中文,但是同样的文字又没必要重复出现,那么如何来制作这个字体包呢?制作的细节大家可以参照威哥的博客:http://1vr.cn/article.asp?id=607  他已经写得很清楚啦。

 

 

最后本文的程序MOMO已经打成包,雨松MOMO希望和大家一起学习,一起进步加油哇咔咔,拉拉~~

下载地址:http://vdisk.weibo.com/s/ab_aA

 

补充:假设你的程序中已经预先将2进制文件做好,如下图所示,你需要把二进制文件放在StreamingAssets这个文件夹中,一定要放在这里。

 

举个例子,放在StreamingAssets中二进制文件打包后,Unity会将这些二进制文件放置在对应平台下的路径下。所以根据不同平台,访问的路径是不一样的。切记,你的二进制文件一定要放在StreamingAssets !!!!!!

01 #if UNITY_EDITOR
02         string filepath = Application.dataPath +"/StreamingAssets"+"/my.xml";
03  
04 #elif UNITY_IPHONE
05       string filepath = Application.dataPath +"/Raw"+"/my.xml";
06  
07 #elif UNITY_ANDROID
08       string filepath = "jar:file://" + Application.dataPath + "!/assets/"+"/my.xml;
09  
10 #endif


2016-03-26 10:50:18 linshuhe1 阅读数 5468

<pre name="code" class="csharp">

        ScriptableObject:经常用于存储一些unity3d本身不能打包的对象(object),比如:字符串,一些类对象等。用这个类型的子类型,则可以用BuildPipeline打包成assetbundle包或者.assets文件供后续使用。

接下来我们通过一个简单的实例来展示如何使用ScriptableObject类:

步骤一:创建一个继承自ScriptableObject的类:

using UnityEngine;
using System.Collections;
using System.Collections.Generic;
[System.Serializable]
/// <summary>
/// 保存表格导出的序列号数据
/// </summary>
public class GameDataScriptable : ScriptableObject {
    /// <summary>
    /// 技能字典
    /// </summary>
    public List<SkillItem> _SkillDictionary = new List<SkillItem>();
    public List<SkillItem> SkillDictionary {
        get { return _SkillDictionary; }
        set { _SkillDictionary = value; }
    }
}

        这里我们希望存在ScriptableObject中的是一个技能字典对象,SkillItem的数据结构可以自行定义,也可以用string或者int等简单数据类型来取代

using UnityEngine;
using System.Collections;
using System;
[System.Serializable]
/// <summary>
/// 表格数据结构
/// </summary>
public class SkillItem
{
    public int _SkillId;
    public string _SkillName;
    public int SkillId
    {
        get { return _SkillId; }
        set { _SkillId = value; }
    }
    public string SkillName
    {
        get { return _SkillName; }
        set { _SkillName = value; }
    }
}

步骤二:创建一个在Unity引擎中使用的编辑器脚本,并且此脚本必须存放在Assets目录下面的Editor文件夹下面,在这样的脚本都继承于Editor类:

using UnityEngine;
using UnityEditor;
using System.Collections;
using System.Collections.Generic;
using System.IO;

public class ToolsMenu:Editor{
    [MenuItem("打包工具/部分资源打包/打包表格数据")]
    public static void BuildConfigData()
    {
        Caching.CleanCache();
	//通过ScriptableObject创建一个对象的实例
	GameDataScriptable gs = ScriptableObject.CreateInstance<GameDataScriptable>();
	//对对象的属性进行赋值
	for(int i=1;i<3;i++){
		SkillItem item = new SkillItem();
		item.SkillId = i;			    
		item.SkillName = "技能" + i;  
		gs.SkillDictionary.Add(item);
	}
	//创建资源文件(可以在编辑器下直接编辑数据)
	AssetDatabase.CreateAsset(gs, "Assets/GameDataConfig.asset");
	//将资源反序列化为一个对象
	 Object o = AssetDatabase.LoadAssetAtPath("Assets/GameDataConfig.asset", typeof(GameDataScriptable));
         string targetPath = "Assets/GameData.assetbundle";
         //assetbundle文件只能在运行时加载,并且只能通过WWW加载
	 BuildPipeline.BuildAssetBundle(o, null, targetPath);
         //删除临时的资源文件
	 AssetDatabase.DeleteAsset("Assets/GameDataConfig.asset");
    }
}

步骤三:运行时加载这个数据资源

using UnityEngine;
using System.Collections;
public class LoadFileTest:MonoBehaviour
{
    IEnumerator Start ()
    {
      WWW www = new WWW("file://" + Application.dataPath + "/../GameDataConfig.assetbundle");
      yield return www;
      //转换资源为Test,这个test对象将拥有原来在编辑器中设置的数据。
      GameDataScriptable test = www.assetBundle.mainAsset as GameDataScriptable;
      Debug.Log("技能1的Id:"+test.SkillDictionary[0].SkillId);
    }
}


补充:这其实是把整个对象实例打包,如果ScriptableObject属性中包括其他的类实例,则这些类需加上[Serializable]序列化。通过这种方法,可以将系统需要的数据(如导表出来的数据等等)打包,加载后直接转换为预定的类型,可以大大加快数据加载读取的速度,具有更高的效率。

2019-09-29 12:47:18 lisa0626 阅读数 47

项目需要做一个安卓端的图片轮播小程序。然后猛然发现一万年过去了安卓端自己还在用www读取本地图片,Assetbundle虽然好用读取也快……但不方便客户自己进行替换图片操作,一个轮播图小程序还要配置一个安卓本地服务器并写一个小工具给客户用来打包,操作就过于繁琐了。

试着用www和文件读取二进制两种方式来读取,读取速度差不多……下面来介绍两种方式。

安卓端路径

安卓端PersistentDataPath的路径具体位置在:/storage/emulated/0/com.companyName.productName/files/底下,将文件复制到对于文件夹即可。

从文件中用二进制直接读取

public void LoadFile(string path)
    {

        DirectoryInfo direction = new DirectoryInfo(path);
        FileInfo[] files = direction.GetFiles("*");
        List<string> imageNames = new List<string>();
        for (int i = 0; i < files.Length; i++)
        {
            if (!files[i].Name.EndsWith(".meta"))
            {
                imageNames.Add(files[i].FullName);
            }
        }
        Total = imageNames.Count;
        for(int j = 0; j < imageNames.Count; j++)
        {
            //StartCoroutine(DownLoadPic("file:///" + path + "/" + files[j].Name));
            byte[] binaryImageData = File.ReadAllBytes(imageNames[j]);
            Texture2D imageTex = new Texture2D(Screen.width,Screen.height);
            imageTex.LoadImage(binaryImageData);
            GameObject ImageObj = Instantiate<GameObject>(prefab, Content);
            ImageObj.name = j.ToString();
            Image image = ImageObj.GetComponent<Image>();
            int width = imageTex.width;
            int height = imageTex.height;

            Sprite sprite = Sprite.Create(imageTex, new Rect(0, 0, width, height), Vector2.zero);
            image.sprite = sprite;
            RectTransform imgTrans = image.GetComponent<RectTransform>();
            float radio = (float)width / height;
            Debug.Log(radio);
            if (height >= width)
            {
                imgTrans.sizeDelta = new Vector2(Screen.height * radio, Screen.height);
            }
            else{
                imgTrans.sizeDelta = new Vector2(Screen.width, Screen.width/radio);
            }
            Draggable draggable = ImageObj.GetComponent<Draggable>();
            draggable.BeginDrag += OnBeginDrag;
            draggable.Dragged += OnDrag;
            draggable.Dragging += OnDragging;
            ImageList.Add(imgTrans);
            imgTrans.anchoredPosition = new Vector2((j - imageNames.Count / 2) * Screen.width, 0);
        }
        OnLoadCompelete();
    }

用www读取

IEnumerator DownLoadPic(string url) {
        WWW picdownloader = new WWW(url);
        yield return picdownloader;
        if (picdownloader.error != null) {
            Debug.LogError(picdownloader.error);
        }
        else if (picdownloader.isDone) {
            Texture2D imageTex = picdownloader.texture;
            GameObject ImageObj = Instantiate<GameObject>(prefab, Content);
            ImageObj.name = ImageCount.ToString();
            Image image = ImageObj.GetComponent<Image>();
            int width = imageTex.width;
            int height = imageTex.height;
           
            Sprite sprite = Sprite.Create(imageTex, new Rect(0, 0, width, height), Vector2.zero);
            image.sprite = sprite;
            RectTransform imgTrans = image.GetComponent<RectTransform>();
            float radio = (float)width / height;
            if (height >= width)
            {
                imgTrans.sizeDelta = new Vector2(Screen.height * radio, Screen.height);
            }
            else
            {
                imgTrans.sizeDelta = new Vector2(Screen.width, Screen.width / radio);
            }
            Draggable draggable = ImageObj.GetComponent<Draggable>();
            draggable.BeginDrag += OnBeginDrag;
            draggable.Dragged += OnDrag;
            draggable.Dragging += OnDragging;
            ImageList.Add(imgTrans);
            imgTrans.anchoredPosition = new Vector2((ImageCount-Total / 2) *Screen.width,0);
            ImageCount++;
            if (ImageCount == Total) {
                OnLoadCompelete();
            }
        }
    }

轮播图核心思想:

在每个子元件上绑上拖拽代码,在拖拽完成后将末尾的图放在最初始。可以用双链表算法优化,这里就直接遍历子节点,写的简单一些。在预制件上绑上Draggable

public class Draggable : MonoBehaviour,IBeginDragHandler, IDragHandler, IEndDragHandler
{
    public UnityAction<PointerEventData> BeginDrag;
    public UnityAction<PointerEventData> Dragging;
    public UnityAction<PointerEventData> Dragged;

    public void OnBeginDrag(PointerEventData eventData)
    {
        if (BeginDrag != null)
        {
            BeginDrag(eventData);
        }
    }

    public void OnDrag(PointerEventData eventData)
    {
        if (Dragging != null)
        {
            Dragging(eventData);
        }
    }

    public void OnEndDrag(PointerEventData eventData)
    {
        if (Dragged != null)
        {
            Dragged(eventData);
        }
    }
}

完整代码路径:

2019-12-10 19:52:58 qq_37254346 阅读数 14

路径

在安卓端一般常用的路径1.StreamingAssetsPath:Application.streamingAssetsPath

                                        2.PersistentDataPath:Application.persistentDataPath

区别:1.StreamingAssets需要我们在编辑器里手动创建的一个文件夹,而PersistentDataPath是当我们程序运行时系统默认创建的文件夹。

           2.当我们把一个APK解压后会得到三个文件夹(assets,lib,res)和3个文件(AndroidManifest,classes,resources),然后打开assets文件夹会发现我们放在StreamingAssets目录下的资源文件都被原封不动的放到了这个目录下,而PersistentDataPath呢,这个目录在我们APK安装目录下的files目录,详细目录:Android/data/com.包名/files

           3.这里最重要的一点是StreamingAssets目录是不支持C#的IO流操作的,但是可以使用Unity的API来读取(www被弃用了,可以使用UnityWebRequest来读取数据),并且这个文件夹是只读文件夹,也就是说不能写入数据(当然,PC/Editor上这个文件夹就没有这个限制了),而PersistentDataPath是可读写文件夹。

一般情况下,可以在程序开始时把StreamingAssets下的资源(AB包等)拷贝到PersistentDataPath目录下读写,也可以直接在StreamingAssets下读取,但不能使用IO流读取。

这里还有一个需要注意的是:c#读取Excel表的库在安卓端程序运行时是不可取的,什么意思呢,换句话说就是c#读取Excel表的库不支持在安卓端动态读取数据,可以在编辑器里把数据转换成JSON文本/二进制文本保存起来,然后动态读取文本的方式,后面博客里我会介绍怎么实现。

 

 

 

unity读取路径

阅读数 370

博文 来自: yang5581682
没有更多推荐了,返回首页