首页 >Unity3D频道 >【Unity3D研究院之游戏开发】 > Unity3D研究院之IOS Android支持中文与本地文件的读取写入(二十七)
2012
05-31

Unity3D研究院之IOS Android支持中文与本地文件的读取写入(二十七)

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

Text.cs

 

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

public class Text : MonoBehaviour {
	//文本中每行的内容
	ArrayList infoall;
	//皮肤资源,这里用于显示中文
	public GUISkin skin;
	void Start ()
	{

		//删除文件
		DeleteFile(Application.persistentDataPath,"FileName.txt");

		//创建文件,共写入3次数据
		CreateFile(Application.persistentDataPath,"FileName.txt","宣雨松MOMO");
		CreateFile(Application.persistentDataPath,"FileName.txt","宣雨松MOMO");
		CreateFile(Application.persistentDataPath ,"FileName.txt","宣雨松MOMO");
		//得到文本中每一行的内容
		infoall = LoadFile(Application.persistentDataPath,"FileName.txt");

	}

   /**
   * path:文件创建目录
   * name:文件的名称
   *  info:写入的内容
   */
   void CreateFile(string path,string name,string info)
   {
   	  //文件流信息
      StreamWriter sw;
      FileInfo t = new FileInfo(path+"//"+ name);
      if(!t.Exists)
      {
      	//如果此文件不存在则创建
      	sw = t.CreateText();
      }
	  else
	  {
	  	//如果此文件存在则打开
	 	sw = t.AppendText();
	  }
	  //以行的形式写入信息
      sw.WriteLine(info);
      //关闭流
      sw.Close();
      //销毁流
      sw.Dispose();
   }  

  /**
   * path:读取文件的路径
   * name:读取文件的名称
   */
   ArrayList LoadFile(string path,string name)
   {
   		//使用流的形式读取
        StreamReader sr =null;
		try{
			sr = File.OpenText(path+"//"+ name);
		}catch(Exception e)
		{
			//路径与名称未找到文件则直接返回空
			return null;
		}
		string line;
		ArrayList arrlist = new ArrayList();
     	while ((line = sr.ReadLine()) != null)
		{
			//一行一行的读取
			//将每一行的内容存入数组链表容器中
  			arrlist.Add(line);
 		}
		//关闭流
		sr.Close();
   		//销毁流
   		sr.Dispose();
		//将数组链表容器返回
		return arrlist;
   }   

  /**
   * path:删除文件的路径
   * name:删除文件的名称
   */

   void DeleteFile(string path,string name)
   {
   		File.Delete(path+"//"+ name);

   }

   void OnGUI()
   {
   		//用新的皮肤资源,显示中文
   		GUI.skin = skin;
   	    //读取文件中的所有内容
   		foreach(string str in infoall)
		{
			//绘制在屏幕当中,哇咔咔!
			GUILayout.Label(str);
		} 

   }

}

 

        代码中头文件需要注意一下,涉及到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按钮即可完成字体配置。

 

Unity3D研究院之IOS Android支持中文与本地文件的读取写入(二十七) - 雨松MOMO程序研究院 - 1

 

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

 

Unity3D研究院之IOS Android支持中文与本地文件的读取写入(二十七) - 雨松MOMO程序研究院 - 2

 

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

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

 

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

Unity3D研究院之IOS Android支持中文与本地文件的读取写入(二十七) - 雨松MOMO程序研究院 - 3

 

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

#if UNITY_EDITOR
		string filepath = Application.dataPath +"/StreamingAssets"+"/my.xml";

#elif UNITY_IPHONE
	  string filepath = Application.dataPath +"/Raw"+"/my.xml";

#elif UNITY_ANDROID
	  string filepath = "jar:file://" + Application.dataPath + "!/assets/"+"/my.xml;

#endif

 

最后编辑:
作者:雨松MOMO
专注移动互联网,Unity3D游戏开发
捐 赠写博客不易,如果您想请我喝一杯星巴克的话?就进来看吧!

Unity3D研究院之IOS Android支持中文与本地文件的读取写入(二十七)》有 83 条评论

  1. wb_yang说:

    在IOS平台下,我修改了文件内容要刷新怎么刷新呢?在编辑器下面是AssetDatabase.Refresh(),但是在IOS平台好像不行。

  2. 解决了就好, 呵呵。。

  3. 张强说:

    老师的包我下下来在windows平台的编译器上运行, Application.persistentDataPath = “”, dataPath有值,很奇怪,不知道有有没有和我一样碰到同样问题的童鞋。貌似在真机上没问题

  4. ming说:

    MOMO老师好,我测试过上面的代码,当我仅使用LoadFile()的代码时不能在Android显示,我试过只有在执行删除、创建后,才能正确读取并显示,好迷惑~~(╯﹏╰)

    • ming说:

      已经解决了,在CreateFile()函数中用Unity的TexAsset.text读取本地文件,即CreateFile(path,TexAsset.text,fileName.txt) 就可以了,只是每次执行都要进行删除和创建,会降低效率

  5. solq说:

    using UnityEngine;
    using System.Collections;
    using System.IO;
    using ICSharpCode.SharpZipLib.Zip;
    using ICSharpCode.SharpZipLib.Core;
    using System;
    public class Test : MonoBehaviour
    {
    string path = “”;

    void Start()
    {
    path = “jar:file://” Application.dataPath “!/assets/”;
    //readFile(“test.txt”);

    // File.WriteAllText(Application.persistentDataPath “/xx2.txt”, “xxxxxxxxxxxxxxxxxxxx”);

    UnZipFile(Application.dataPath, “assets”);

    }

    #region 解压资料处理fn

    //判断是否已经解压
    bool checkDecompressingFiles(string flag_file)
    {
    if (!File.Exists(Application.persistentDataPath “/” flag_file))
    {
    File.WriteAllText(Application.persistentDataPath “/” flag_file, “a”);
    return false;
    }
    return true;
    }

    /*
    * 没有测试过
    ICSharpCode.SharpZipLib.Zip.FastZip zip = new ICSharpCode.SharpZipLib.Zip.FastZip();
    zip.CreateZip(“C:\foo.zip”, “C:\待压缩的文件夹”, true, “”); //第三个参数表示是否压缩子文件夹
    zip.ExtractZip(“C:\foo.zip”, “C:\压缩后存放的文件夹”, “”);
    如果我们只想压缩目录中的一个或部分文件,或者我们只想解压文件中的一个或部分文件,怎么办呢?那就得把最后一个参数用上,它是字符串类型的正则表达式,比如只压缩 ini 文件用:”^.*(.ini)$”。
    */

    //用第三方工具去读取 zip
    void UnZipFile(string zipFilePath,string dir)
    {
    if (checkDecompressingFiles(“init.txt”)) {
    stringToEdit = ” 已经解压过了”;
    return;
    }else
    stringToEdit = ” 第一次解压”;
    using (ZipInputStream s = new ZipInputStream(File.OpenRead(zipFilePath)))
    {
    ZipEntry theEntry;
    while ((theEntry = s.GetNextEntry()) != null)
    {
    string directoryName = Path.GetDirectoryName(theEntry.Name);
    string fileName = Path.GetFileName(theEntry.Name);
    // print(“directoryName:” directoryName);
    // print(“fileName:” fileName);

    if (directoryName.Length > 0 && directoryName.Contains(dir))
    {
    //stringToEdit = ” directoryName:” directoryName “n”;
    Directory.CreateDirectory(Application.persistentDataPath “/” directoryName);
    if (fileName != string.Empty)
    {
    using (FileStream streamWriter = File.Create(Application.persistentDataPath “/” theEntry.Name))
    {

    int size = 2048;
    byte[] data = new byte[2048];
    while (true)
    {
    size = s.Read(data, 0, data.Length);
    if (size > 0)
    streamWriter.Write(data, 0, size);
    else
    break;
    }
    }
    }
    }

    }
    }
    }

    //直接用 unty www 去读取 jar 跟 zip 标准差不多吧
    void readFile(string file)
    {
    path = file;

    if (File.Exists(path))
    {
    stringToEdit = “yes”;
    }
    else
    {
    stringToEdit = “no”;

    WWW www = new WWW(path);
    while (!www.isDone) { }

    stringToEdit = ” ” http://www.text;

    stringToEdit =” ReadAllText:” File.ReadAllText(path);
    }
    }
    #endregion

    private string stringToEdit = “”;

    void Update ()
    {
    //点击手机返回键关闭应用程序
    if (Input.GetKeyDown(KeyCode.Escape) || Input.GetKeyDown(KeyCode.Home) )
    {
    Application.Quit();
    }
    }

    void OnGUI()
    {

    GUILayout.TextField(“persistentDataPath:” Application.persistentDataPath);
    GUILayout.TextField(“dataPath:” Application.dataPath);
    GUILayout.TextField(“temporaryCachePath:” Application.temporaryCachePath);

    stringToEdit = GUILayout.TextArea (stringToEdit, GUILayout.Width(300),GUILayout.Height(250));
    }

    }
    //用到解压的库。。。http://www.icsharpcode.net/OpenSource/SharpZipLib/Download.aspx
    //感谢:雨松MOMO https://www.xuanyusong.com/

  6. solq说:

    using UnityEngine;
    using System.Collections;
    using System.IO;
    using ICSharpCode.SharpZipLib.Zip;
    using ICSharpCode.SharpZipLib.Core;
    using System;
    public class Test : MonoBehaviour
    {
    string path = “”;

    void Start()
    {
    path = “jar:file://” + Application.dataPath + “!/assets/”;
    //readFile(“test.txt”);

    // File.WriteAllText(Application.persistentDataPath + “/xx2.txt”, “xxxxxxxxxxxxxxxxxxxx”);

    UnZipFile(Application.dataPath, “assets”);

    }

    #region 解压资料处理fn

    //判断是否已经解压
    bool checkDecompressingFiles(string flag_file)
    {
    if (!File.Exists(Application.persistentDataPath + “/” + flag_file))
    {
    File.WriteAllText(Application.persistentDataPath + “/” + flag_file, “a”);
    return false;
    }
    return true;
    }

    /*
    * 没有测试过
    ICSharpCode.SharpZipLib.Zip.FastZip zip = new ICSharpCode.SharpZipLib.Zip.FastZip();
    zip.CreateZip(“C:\foo.zip”, “C:\待压缩的文件夹”, true, “”); //第三个参数表示是否压缩子文件夹
    zip.ExtractZip(“C:\foo.zip”, “C:\压缩后存放的文件夹”, “”);
    如果我们只想压缩目录中的一个或部分文件,或者我们只想解压文件中的一个或部分文件,怎么办呢?那就得把最后一个参数用上,它是字符串类型的正则表达式,比如只压缩 ini 文件用:”^.*(.ini)$”。
    */

    //用第三方工具去读取 zip
    void UnZipFile(string zipFilePath,string dir)
    {
    if (checkDecompressingFiles(“init.txt”)) {
    stringToEdit += ” 已经解压过了”;
    return;
    }else
    stringToEdit += ” 第一次解压”;
    using (ZipInputStream s = new ZipInputStream(File.OpenRead(zipFilePath)))
    {
    ZipEntry theEntry;
    while ((theEntry = s.GetNextEntry()) != null)
    {
    string directoryName = Path.GetDirectoryName(theEntry.Name);
    string fileName = Path.GetFileName(theEntry.Name);
    // print(“directoryName:” + directoryName);
    // print(“fileName:” + fileName);

    if (directoryName.Length > 0 && directoryName.Contains(dir))
    {
    //stringToEdit += ” directoryName:” + directoryName+”n”;
    Directory.CreateDirectory(Application.persistentDataPath + “/” + directoryName);
    if (fileName != string.Empty)
    {
    using (FileStream streamWriter = File.Create(Application.persistentDataPath + “/” + theEntry.Name))
    {

    int size = 2048;
    byte[] data = new byte[2048];
    while (true)
    {
    size = s.Read(data, 0, data.Length);
    if (size > 0)
    streamWriter.Write(data, 0, size);
    else
    break;
    }
    }
    }
    }

    }
    }
    }

    //直接用 unty www 去读取 jar 跟 zip 标准差不多吧
    void readFile(string file)
    {
    path+= file;

    if (File.Exists(path))
    {
    stringToEdit = “yes”;
    }
    else
    {
    stringToEdit = “no”;

    WWW www = new WWW(path);
    while (!www.isDone) { }

    stringToEdit += ” ” + http://www.text;

    stringToEdit+=” ReadAllText:”+File.ReadAllText(path);
    }
    }
    #endregion

    private string stringToEdit = “”;

    void Update ()
    {
    //点击手机返回键关闭应用程序
    if (Input.GetKeyDown(KeyCode.Escape) || Input.GetKeyDown(KeyCode.Home) )
    {
    Application.Quit();
    }
    }

    void OnGUI()
    {

    GUILayout.TextField(“persistentDataPath:” + Application.persistentDataPath);
    GUILayout.TextField(“dataPath:” + Application.dataPath);
    GUILayout.TextField(“temporaryCachePath:” + Application.temporaryCachePath);

    stringToEdit = GUILayout.TextArea (stringToEdit, GUILayout.Width(300),GUILayout.Height(250));
    }

    }
    //用到解压的库。。。http://www.icsharpcode.net/OpenSource/SharpZipLib/Download.aspx
    //感谢:雨松MOMO https://www.xuanyusong.com/

  7. solq说:

    解决了,,,下面说下步骤

    test.txt

    AssetsPluginsAndroidassetstest.txt

    void readFile(string file)
    {
    path = “jar:file://” Application.dataPath “!/assets/” file;

    if (File.Exists(path))
    {
    stringToEdit = “yes”;
    }
    else
    {
    stringToEdit = “no”;

    WWW www = new WWW(path);
    while (!www.isDone) { }

    stringToEdit = ” ” http://www.text;

    }
    }
    不知道为什么 File.Exists(path)会检测不到文件,,,不过能读取就可以了
    打下广告
    http://www.cnblogs.com/solq/archive/2012/05/21/2511522.html

  8. solq说:

    解决了,,,下面说下步骤

    test.txt

    AssetsPluginsAndroidassetstest.txt

    void readFile(string file)
    {
    path = “jar:file://” + Application.dataPath + “!/assets/” + file;

    if (File.Exists(path))
    {
    stringToEdit = “yes”;
    }
    else
    {
    stringToEdit = “no”;

    WWW www = new WWW(path);
    while (!www.isDone) { }

    stringToEdit += ” ” + http://www.text;

    }
    }
    不知道为什么 File.Exists(path)会检测不到文件,,,不过能读取就可以了
    打下广告
    http://www.cnblogs.com/solq/archive/2012/05/21/2511522.html

  9. solq说:

    我刚才又查了下, unity Application.dataPath 是向指 /data/app/xxx.xxx.xxx.apk 的,查看 view 可以找到里面的资源,,,
    但是我用
    void readFile(string file)
    {
    path = “jar:file://” Application.dataPath “!/assets/” file;

    if (File.Exists(path))
    {
    stringToEdit = “yes”;
    }
    else
    {
    stringToEdit = “no”;
    }
    }
    检测不到文件。。。这又怎么办。。。就差一点了…..

  10. solq说:

    我刚才又查了下, unity Application.dataPath 是向指 /data/app/xxx.xxx.xxx.apk 的,查看 view 可以找到里面的资源,,,
    但是我用
    void readFile(string file)
    {
    path = “jar:file://” + Application.dataPath + “!/assets/” + file;

    if (File.Exists(path))
    {
    stringToEdit = “yes”;
    }
    else
    {
    stringToEdit = “no”;
    }
    }
    检测不到文件。。。这又怎么办。。。就差一点了…..

  11. solq说:

    呵呵,回复真快,不是的,,,比如说 在 unity assets 目录里有个test.txt 文件,,,我安装后来怎么访问呢?

  12. solq说:

    android ,ios 的群也开了,,,开个 unity 的吧。。。。

  13. solq说:

    你好,博主,我也正找之方面读取 android 文件的资料
    我发觉用 unity 生成 apk包,安装好后, unity的资源找不到在那里目录,查了下安装app的目录
    unity Application.persistentDataPath 是指向 /data/data/xxx.xxx.xx/files/ 里
    我是想,找不到就想办法 安装好之后,把unity 资源复制到 /data/data/xxx.xxx.xx/files/ 里就可以,,
    但是我不是很了解 android 打包是怎样的,博主有遇到这个问题吗?
    这个能实现吗?

  14. solq说:

    你好,博主,我也正找之方面读取 android 文件的资料
    我发觉用 unity 生成 apk包,安装好后, unity的资源找不到在那里目录,查了下安装app的目录
    unity Application.persistentDataPath 是指向 /data/data/xxx.xxx.xx/files/ 里
    我是想,找不到就安装里之后,把unity 资源复制到 /data/data/xxx.xxx.xx/files/ 里就可以,,
    但是我不是很了解 android 打包是怎样的,博主有遇到这个问题吗?

  15. solq说:

    不错。。。。请问下载的提取码是???

  16. 前来支持!!一起加油!

  17. 龙人说:

    来顶一个,哈哈哈

留下一个回复

你的email不会被公开。 必填项已用 * 标注。