Unity3d通用工具类之数据配置加载类-ini配置文件加载
上次我们讲过xml文件的加载配置管理,今天我们换个配置文件,也是比较常见的配置文件.ini格式的数据。
按照国际管理先贴一张啥是.ini文件:
这里我们分类下,总的来说.ini文件就是里面保存多有数据的头,他的下面包含与之相关的字段数据(采用key-value格式)。
ok,知道格式之后,我们写个IniFile数据管理类:
首先,我们定义他有哪些接口:
肯定他需要加载一个配置文件,那么就定义:
1.public void LoadFromFile(string fileName)
还有我们需要取得某个头部下面的key的value,那么就需要定义:
2.public string GetValue(string sectionName, string key, string defaultValue)
sectionName代表的是头部名称,key代表键值,value代表对应这个键值的值,如果没有发现这个key,就返回默认的值defaultValue。
因为一个配置文件有多个头部,那么我们就需要定义一个头部类来管理,符合类的单一职责。
所以这里得在定义一个IniSection头部类。
他包含哪些数据:
1.头部名称:
private string sectionName;
2.键值对:
private Dictionary<string, string> m_dicKeyValue;
在IniFile类里面维护一个头部列表缓存:
3.private List<IniSection> m_sectionList;
在从文件中加载的时候初始化他,也就是LoadFromFile()方法里面,初始化所有头部的数据。
IniFile.cs:
public class IniFile
{
private List<IniSection> m_sectionList;
public IniFile()
{
m_sectionList = new List<IniSection>();
}
public void LoadFromFile(string fileName)
{
string strFullPath = Application.dataPath + "/" + fileName;
if (!File.Exists(strFullPath))
{
return;
}
using (FileStream fs = new FileStream(strFullPath, FileMode.Open))
{
LoadFromStream(fs);
}
}
/// <summary>
/// 取得配置文件中所有的头名称
/// </summary>
/// <returns></returns>
public List<string> GetAllSectionName()
{
List<string> sectionList = new List<string>();
foreach (var sec in m_sectionList)
{
sectionList.Add(sec.SectionName.ToLower());
}
return sectionList;
}
/// <summary>
/// 取得头部相关的value
/// </summary>
/// <param name="sectionName"></param>
/// <param name="key"></param>
/// <param name="defaultValue"></param>
/// <returns></returns>
public string GetValue(string sectionName, string key, string defaultValue)
{
IniSection section = GetSection(sectionName);
if (section != null)
{
return section.GetValue(key, defaultValue);
}
return defaultValue;
}
private void LoadFromStream(FileStream fs)
{
using (StreamReader sr = new StreamReader(fs))
{
m_sectionList.Clear();
string line = null;
IniSection section = null;
int equalSignPos = 0;//=号的标记的位置
string key, value;
while (true)
{
line = sr.ReadLine();
if (null == line)
{
break;
}
line = line.Trim();
if (line == "")
{
continue;
}
//跳过注释
if (line.Length >= 2 && line[0] == '/' && line[1] == '/')
{
continue;
}
if (line[0] == '[' && line[line.Length - 1] == ']')
{
//移除首尾的'[]'
line = line.Remove(0, 1);
line = line.Remove(line.Length - 1, 1);
//去SectionList缓存中找是否存在这个Section
section = GetSection(line);
//如果没有找到就直接new一个
if (null == section)
{
section = new IniSection(line);
m_sectionList.Add(section);
}
}
else
{
//就是在这个头下面的数据字段,key-value格式
equalSignPos = line.IndexOf('=');
if (equalSignPos != 0)
{
key = line.Substring(0, equalSignPos);
value = line.Substring(equalSignPos + 1, line.Length - equalSignPos - 1);
section.AddKeyValue(key, value);
}
else
{
Debug.LogWarning("value为空");
}
}
}
}
}
/// <summary>
/// 从缓存中找Section
/// </summary>
/// <param name="sectionName"></param>
/// <returns></returns>
private IniSection GetSection(string sectionName)
{
foreach (var section in m_sectionList)
{
if (section.SectionName.ToLower() == sectionName.ToLower())
{
return section;
}
}
return null;
}
}
IniSection.cs:
/// <summary>
/// ini头部+数据
/// </summary>
public class IniSection
{
private string sectionName;
private Dictionary<string, string> m_dicKeyValue;
public string SectionName
{
get { return this.sectionName; }
set { this.sectionName = value; }
}
public IniSection(string name)
{
this.sectionName = name;
this.m_dicKeyValue = new Dictionary<string, string>();
}
/// <summary>
/// 添加key-value的值
/// </summary>
/// <param name="key"></param>
/// <param name="value"></param>
public void AddKeyValue(string _key,string _value)
{
string value = null;
if (m_dicKeyValue.TryGetValue(_key, out value))
{
if (value != null)
{
m_dicKeyValue[_key] = _value;
}
}
else
{
m_dicKeyValue.Add(_key, _value);
}
}
/// <summary>
/// 根据key取得value,如果没有取到就返回默认的值
/// </summary>
/// <param name="key"></param>
/// <param name="defaultValue"></param>
/// <returns></returns>
public string GetValue(string key, string defaultValue)
{
string value = null;
m_dicKeyValue.TryGetValue(key, out value);
if (m_dicKeyValue.TryGetValue(key, out value))
{
return value;
}
return defaultValue;
}
}
Ok,我们进行下测试,写个ServerData.cs类,继承MonoBehavior:
using UnityEngine;
using System.Collections;
public class ServerData : MonoBehaviour
{
public string m_cfgName = "Server.ini";
public void Load()
{
IniFile ini = new IniFile();
ini.LoadFromFile(m_cfgName);
foreach (var name in ini.GetAllSectionName())
{
if (string.Equals(name, "serverinfo"))
{
Debug.Log(ini.GetValue(name, "IP", ""));
}
}
}
public void Start()
{
Load();
}
}
可以看到在Console中打印出配置文件的数据:
这个数据类我写的有问题,这里只是我测试用的,按正常的开发是不能继承mono,因为每个数据类都需要Load,还有会有Destory(Dispose)销毁。
所以定义一个接口:
public interface IClientData
{
bool Load();
void Destroy();
}
让所有的数据类都实现这个接口,然后在搞个数据管理器(单例),在Init里面加载所有的数据类,就拿ServerData来演示:
using UnityEngine;
using System.Collections;
public class ServerData : IClientData
{
public string m_cfgName = "Server.ini";
public bool Load()
{
IniFile ini = new IniFile();
ini.LoadFromFile(m_cfgName);
foreach (var name in ini.GetAllSectionName())
{
if (string.Equals(name, "serverinfo"))
{
Debug.Log(ini.GetValue(name, "IP", ""));
}
}
return true;
}
public void Destroy()
{
}
}
ClientDataManager.cs:
using UnityEngine;
using System.Collections;
public class ClientDataManager
{
private static ClientDataManager m_oInstance;
public static ClientDataManager Instance
{
get
{
if (m_oInstance == null)
{
m_oInstance = new ClientDataManager();
}
return m_oInstance;
}
}
public ServerData ServerData;
public ClientDataManager()
{
ServerData = new ServerData();
}
public void Init()
{
ServerData.Load();
}
}
Ok,搞个驱动类:Driver.cs:
using UnityEngine;
using System.Collections;
public class Driver : MonoBehaviour {
// Use this for initialization
void Start () {
ClientDataManager.Instance.Init();
}
// Update is called once per frame
void Update () {
}
}
这样,我们假如说在ClientDataManager里面添加所有的数据类,他直接在Driver驱动的时候就全部加载到内存中了。
上面的执行结果应该跟之前的类似。