一、前言
在Unity中读写Json文件已经有非常好的工具,可以将Json文件和结构体数据进行相互转换,如图1所示,在Unity Asset Store中搜JSON.NET可以找到该插件,非常好用。我在此插件的基础上,融合了Windows的文件窗口,即打开和存储Json文件的时候可
![](https://i-blog.csdnimg.cn/blog_migrate/d370dac6a283a7ded4d160a5396d03d0.png)
以获取Windows的窗口,选择保存和读取Json文件的路径。最后,实现了在Android上的读写Json文件。
二、实现
2.1、实现读写文件的窗口
代码如下:该类提供了一个Open_WindowFile方法,当参数"isSaveFile"为true时弹出窗口保存文件,false时弹出窗口打开文件,默认为false。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Runtime.InteropServices;//调用外部库,需要引用命名空间
using System;
using System.Threading;
public class Global_Windows {
public static Global_Windows M_Instance
{
get
{
if (_instance == null)
{
_instance = new Global_Windows();
}
return _instance;
}
}
private openFileName ofn = new openFileName();
private static Global_Windows _instance;
[DllImport("User32.dll", SetLastError = true, ThrowOnUnmappableChar = true, CharSet = CharSet.Auto)]
public static extern int MessageBox(IntPtr handle, String message, String title, int type);//具体方法
[DllImport("Comdlg32.dll", SetLastError = true, ThrowOnUnmappableChar = true, CharSet = CharSet.Auto)]
public static extern bool GetOpenFileName([In, Out] openFileName ofn);
[DllImport("Comdlg32.dll", SetLastError = true, ThrowOnUnmappableChar = true, CharSet = CharSet.Auto)]
public static extern bool GetSaveFileName([Out, In] openFileName ofn);
/// <summary>
/// 打开某个格式的文件,并返回该文件的地址
/// </summary>
/// <param name="dataType">该文件的格式</param>
/// <param name="isSaveFile">true为保存文件,false为只是打开文件,默认为false</param>
/// <returns></returns>
public string Open_WindowFile(string dataType,bool isSaveFile=false)
{
string tempURL = string.Empty;
ofn.structSize = Marshal.SizeOf(ofn);
ofn.filter = dataType+"\0*."+ dataType + "*\0\0";
// ofn.filter = "json\0*.json*\0\0";
ofn.file = new string(new char[256]);
ofn.maxFile = ofn.file.Length;
ofn.fileTittle = new string(new char[64]);
ofn.maxFileTittle = ofn.fileTittle.Length;
string path = Application.streamingAssetsPath;
path = path.Replace('/', '\\');
ofn.initialDir = path;
ofn.tittle = "Open Project";
ofn.defExt = dataType;
ofn.flags = 0x00080000 | 0x00001000 | 0x00000800 | 0x00000200 | 0x00000008;
if (isSaveFile&& GetSaveFileName(ofn))
{
tempURL = ofn.file;
}
else if(!isSaveFile&&GetOpenFileName(ofn))
{
tempURL = ofn.file;
}
return tempURL;
}
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public class openFileName
{
public int structSize = 0;
public IntPtr digOwner = IntPtr.Zero;
public IntPtr instance = IntPtr.Zero;
public String filter = null;
public String customFilter = null;
public int maxCustFilter = 0;
public int filterIndex = 0;
public String file = null;
public int maxFile = 0;
public String fileTittle = null;
public int maxFileTittle = 0;
public String initialDir = null;
public String tittle = null;
public int flags = 0;
public short fileoffset = 0;
public short fileExtension = 0;
public String defExt = null;
public IntPtr custData = IntPtr.Zero;
public IntPtr hook = IntPtr.Zero;
public String templataName = null;
public IntPtr reservedPtr = IntPtr.Zero;
public int resveredInt = 0;
public int flagsEx = 0;
}
2.2、实现Json文件的读写
代码如下:保存Json文件的时候先打开窗口获取保存文件的类型和路径,然后将结构体数据序列化成字符串,使用JsonConvert.SerializeObject方法将数据序列化。下面的代码可以序列化结构体中的数组或列表。读取Json文件的时候,首先会判断路径是否为
/// <summary>
/// 将结构体数据保存成JSON文件
/// </summary>
/// <param name="JSONFilePath"></param>
/// <param name="data"></param>
public static bool SaveData_JSON(object data)
{
bool isSaveSucced = true;
string JSONFilePath = Global_Windows.M_Instance.Open_WindowFile("json", true);
#region 将结构体添加数据转换成JSON文件并存储
try
{
FileInfo file = new FileInfo(JSONFilePath);
//判断有没有文件,有则打开文件,,没有创建后打开文件
StreamWriter sw = file.CreateText();
string json = string.Empty;
var settings = new JsonSerializerSettings()
{
TypeNameHandling = TypeNameHandling.All
};
json = JsonConvert.SerializeObject(data, settings);
// Debug.Log(json);
//将转换好的字符串存进文件,
sw.WriteLine(json);
//注意释放资源
sw.Close();
sw.Dispose();
}
catch (Exception e)
{
Debug.Log(e.Message);
isSaveSucced = false;
}
return isSaveSucced;
#endregion
}
/// <summary>
/// 读取文件夹里的JSON文件,并转换成对应的结构体,
/// 默认没有路径的会自动打开文件夹选择窗口
/// </summary>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
public static T ReadData_JSON<T>(string jsonURL = null)
{
T tempT = default(T);
string JSONFilePath = jsonURL;
#if UNITY_STANDALONE_WIN || UNITY_EDITOR
if (null == JSONFilePath)
{
JSONFilePath = Global_Windows.M_Instance.Open_WindowFile("json", false);
}
#endif
try
{
string tempStrData = string.Empty;
//#if UNITY_STANDALONE_WIN || UNITY_EDITOR
// StreamReader sr = new StreamReader(JSONFilePath, Encoding.UTF8);//安卓平台不能使用这个读取只能使用www
// tempStrData = sr.ReadToEnd();
WWW www = new WWW(JSONFilePath);
while (!www.isDone)
{
// Debug.Log("正在读取!");
}
tempStrData = www.text;
if (tempStrData.Length == 0 || string.Empty == tempStrData || null == tempStrData)
{
#if UNITY_STANDALONE_WIN || UNITY_EDITOR
Global_Windows.MessageBox(IntPtr.Zero, "JSON文件内容为空!", "确认", 0);
#endif
Debug.Log("JSON文件内容为空!");
return tempT;
}
var settings = new JsonSerializerSettings()
{
TypeNameHandling = TypeNameHandling.All
};
tempT = JsonConvert.DeserializeObject<T>(tempStrData, settings);
// Debug.Log(tempStrData);
}
catch (Exception e)
{
Debug.Log(e.Message);
#if UNITY_STANDALONE_WIN || UNITY_EDITOR
Global_Windows.MessageBox(IntPtr.Zero, "读取JSON异常" + e.Message, "确认", 0);
#endif
return tempT;
}
// Global_Windows.MessageBox(IntPtr.Zero, "读取JSON数据成功", "确认", 0);
return tempT;
}
空,如果为空就开启窗口读取选择Json文件读取,如果不为空则不弹窗直接读取,非常方便。 另外,读写数据异常的时候会弹出Windows的消息窗口,代码如下:
Global_Windows.MessageBox(IntPtr.Zero, "读取JSON异常" + e.Message, "确认", 0);
这个窗口时独立于Unity的,如果想单独使用在工程中也可以直接像上面那样调用。
2.3、规范Json文件的保存路径
为了将Json文件的读写路径都统一到指定的路径下,还需要增加一个统一路径的代码,如下:这个路可以在安卓系统上运行且读写Json文件,在Winddows下的路径为和工程同级目录
/// <summary>
/// 获取跟工程相同目录的路径,如“E:/ZXB/MyProject/Asset/",去掉后面两个就得到和工程同级的目录为:“E:/ZXB”
/// </summary>
/// <returns></returns>
private static string GetCurProjectFilePath()
{
string strPath = string.Empty;
#if UNITY_ANDROID
strPath = "file:///storage/emulated/0/";
#elif UNITY_STANDALONE_WIN || UNITY_EDITOR
string[] strTempPath = Application.dataPath.Split('/');
//去掉后面两个,获取跟工程相同目录的路径,如“E:/ZXB/MyProject/Asset/",去掉后面两个就得到和工程同级的目录为:“E:/ZXB”
for (int i = 0; i < strTempPath.Length - 2; i++)
{
strPath += strTempPath[i] + "/";
}
#endif
return strPath;
}
三、总结
3.1、考虑Json文件序列化数组或列表的时候要注意参数设置为TypeNameHandling.All;
3.2、安卓平台读取Json文件的时候只能用WWW类来获取。