Unity3d通用工具类之数据配置加载类-ini配置文件加载

上次我们讲过xml文件的加载配置管理,今天我们换个配置文件,也是比较常见的配置文件.ini格式的数据。

 

按照国际管理先贴一张啥是.ini文件:

unity手机游戏存档文件在哪里_数据

这里我们分类下,总的来说.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中打印出配置文件的数据:

unity手机游戏存档文件在哪里_加载_02

这个数据类我写的有问题,这里只是我测试用的,按正常的开发是不能继承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驱动的时候就全部加载到内存中了。

上面的执行结果应该跟之前的类似。