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驅動的時候就全部加載到內存中了。
上面的執行結果應該跟之前的類似。
