从外部读取文件进行数据交换

作为小白的我,今天接到一个项目,让实现外部动态替换菜单(包括食物图片,名称,价格),一下子有点懵,以前没写过,入行还没半年,稍微深的东西还是有些陌生,这个项目由于时间比较赶,所以领导没让我写,让我们部门一位大佬不到半天时间写出来了,我拿过来看了半天,以下是我自己的总结:
首先说一下思想,想要从外部动态替换菜单,需要让我们的程序启动时读取外部文件里面的图片,然后替换到UI上面,名称和价格创建一个xml文件,通过解析xml文件来读取。当这个外部文件和xml文件,增加或者删除时,程序会进行监听,来同步数据(需要重新启动程序),下面是代码演示。
首先创建文件流读取文件
`using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Xml;
using UnityEngine.UI;
using System.IO;
using System; //引用命名空间下

///
/// 读取StreamingAssets目录下的Menu.xml配置文件,从Menu文件夹中读取出图片
///
public class LoadMenu : MonoBehaviour
{
//一道菜的信息
class DishInfo
{
//菜名
public string name;
//价格
public string price;
}

//-----------------------------------UI----------------------------------//
//up,down两个按钮
public Button upBtn;
public Button downBtn;

//要显示的10个imgUI
public Image[] imgs;
//要显示的10个文字描述
public Text[] names;
//要显示的10个价格描述
public Text[] prices;
//要显示的10个小箭头
public Image[] Arrow;

//---------------------------------配置参数------------------------------//
//配置文件
private XmlDocument xmlDoc = new XmlDocument();
//配置文件的路径
private string configPath;
//存放菜单图片的路径
private string menuPath;

//菜单<菜的索引编号,菜的详细信息>
private List<DishInfo> dishs = new List<DishInfo>();
//保存所有图片精灵
private List<Sprite> sprites = new List<Sprite>();

//一行显示几个图?
private int rowNum = 5;
//显示几行?
private int showRows = 2;

//---------------------------------运行参数------------------------------//
//显示菜品的第几行
private int count = 0;

void Start ()
{      
    //*****绑定按钮事件*****//
    upBtn.onClick.AddListener(OnUpButtonClick);
    downBtn.onClick.AddListener(OnDownButtonClick);

    //项目当前路径
     string curPath = System.Environment.CurrentDirectory;
   // string curPath = System.AppDomain.CurrentDomain.SetupInformation.ApplicationBase;
    //需要读取的菜单配置路径
    configPath = curPath + "/菜单编辑.xml";
    //需要读取的菜单图片路径
    menuPath = curPath + "/菜单配图/";
    //加载配表到xmlDoc
    ConfigUtility.LoadXmlFromFile(xmlDoc, configPath);
    //读取递归深度=2的所有元素
    Dictionary<string, Dictionary<string, string>> dics = ConfigUtility.GetSub2DataInHierarchy(xmlDoc, null);

    foreach (var kv in dics)
    {
        ///Debug.Log(":::::::::::::::::"+kv.Key);//调试代码

        DishInfo di = new DishInfo();
        foreach (var kv2 in kv.Value)
        {
            Debug.Log(kv2.Key+"=="+kv2.Value);//调试代码
            if (kv2.Key == "菜名")
                di.name = kv2.Value;
            else if(kv2.Key == "价格")
                di.price = kv2.Value;
        }
        dishs.Add(di);
    }

    //加载图像精灵
    LoadMenuByIO();

    upBtn.interactable = false;
    if(dishs.Count<= rowNum* showRows)
    {
        downBtn.interactable = false;
    }

    //刷新这n张展示图,名字,价格
    UpdateMenu();

}

void Update ()
{
	
}

//按钮绑定事件
void OnUpButtonClick()
{
    if(count>0)
    {
        count -= 1;
        //刷新这n张展示图,名字,价格
        UpdateMenu();
        downBtn.interactable = true;

        if (count == 0)
        {
            upBtn.interactable = false;
        }
    }      
}
void OnDownButtonClick()
{
    int maxRow = (int)Mathf.Ceil((float)dishs.Count / (float)rowNum) - 2;
    if (count < maxRow) 
    {
        count += 1;
        //刷新这n张展示图,名字,价格
        UpdateMenu();
        upBtn.interactable = true;

        if(count == maxRow)
        {
            downBtn.interactable = false;
        }
    }   
}

//根据索引获取菜的名字和价格信息
public void GetDishNameAndPriceByIndex(int index,out string name,out string price)
{
    name = dishs[index].name; 
    price = dishs[index].price;
}
//根据索引获取菜的名字信息
public string GetDishNameByIndex(int index)
{
    return dishs[index].name;
}
//根据索引获取菜的价格信息
public string GetDishPriceByIndex(int index)
{
    return dishs[index].price;
}

private void LoadMenuByIO()//主要用来读取文件夹中的图片
{
    for (int i = 0; i < dishs.Count; ++i)
    {
        string picPath = menuPath + dishs[i].name + ".jpg";

        try
        {
            //创建文件流
            FileStream fs = new FileStream(picPath, FileMode.Open, FileAccess.Read);
            fs.Seek(0, SeekOrigin.Begin);

            //创建文件长度的缓冲区
            byte[] bytes = new byte[fs.Length];
            //读取文件
            fs.Read(bytes, 0, (int)fs.Length);
            //关闭流
            fs.Close();

            //创建Texture
            int width = 248;
            int height = 166;
            Texture2D texture2D = new Texture2D(width, height);
            texture2D.LoadImage(bytes);

            sprites.Add(Sprite.Create(texture2D, new Rect(0, 0, width, height), new Vector2(0.5f, 0.5f)));
        }
        catch
        {
            PopMessage.MessageBox(IntPtr.Zero, "请检查第"+ (i + 1).ToString() + "道菜的菜名和图片名是否一致!", "确认", 0);               
        }       
    }  
}

private void UpdateMenu()
{
    //刷新这n张展示图,名字,价格
    for (int i = 0; i < imgs.Length; ++i)
    {
        //得到显示的第一个的信息
        int index = count * rowNum + i;           
       // Debug.Log(":::::"+ index.ToString());
       // Debug.Log(sprites.Count);
        if (index < sprites.Count)
        {
            imgs[i].enabled = true;
            names[i].enabled = true;
            prices[i].enabled = true;
            Arrow[i].enabled = true;

            imgs[i].sprite = sprites[index];
            names[i].text = dishs[index].name;
            prices[i].text = dishs[index].price;
        }
        else
        {
            imgs[i].enabled = false;
            names[i].enabled = false;
            prices[i].enabled = false;
            Arrow[i].enabled= false;
        }
    }
}

}
在这里插入图片描述
解析如图所示的xml文件
在using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Xml;

public class ConfigUtility
{
///
/// 从文件读取xml文件
///
/// XmlDocument
/// Xml文件路径
public static void LoadXmlFromFile(XmlDocument doc, string path)
{
if (doc == null)
doc = new XmlDocument();

    doc.Load(path);
    //XmlElement rootElement = doc.DocumentElement;
    //XmlNodeList ndlist = rootElement.ChildNodes;
}
/// <summary>
/// 保存xml到文件
/// </summary>
/// <param name="doc">XmlDocument</param>
/// <param name="path">Xml文件路径</param>
public static void SaveXmlToFile(XmlDocument doc, string path)
{
    doc.Save(path);
}

/// <summary>
/// 取string类型的值(当前Xml节点)
/// </summary>
/// <param name="doc">XmlDocument</param>
/// <param name="ss">节点路径</param>
/// <returns></returns>
public static string GetStringValue(XmlDocument doc, params string[] ss)
{
    //根节点
    XmlElement rootElement = doc.DocumentElement;
    XmlNode cur = GetXmlNodeByNames(rootElement, ss);
    foreach (string s in ss)
    {
        cur = GetXmlNodeByName(cur, s);
    }
    return cur.InnerText;
}

/// <summary>
/// 取List<string>类型的值(当前Xml节点),递归深度=0
/// </summary>
/// <param name="doc">XmlDocument</param>
/// <param name="div">字符串分割符</param>
/// <param name="ss">节点路径</param>
/// <returns></returns>
public static List<string> GetStringValues(XmlDocument doc,string split, params string[] ss)
{
    string str = GetStringValue(doc, ss);
    return Assist.SplitString(str, split);
}

/// <summary>
/// 取所有子节点的值(下一层子节点们),,递归深度=1
/// </summary>
/// <param name="doc"></param>
/// <param name="ss"></param>
/// <returns></returns>
public static Dictionary<string,string> GetSubStrKeysStrValues(XmlDocument doc, params string[] ss)
{
    Dictionary<string, string> ret = new Dictionary<string, string>();
    //根节点
    XmlElement rootElement = doc.DocumentElement;
    XmlNode aimNd = GetXmlNodeByNames(rootElement,ss); 

    foreach (XmlNode nd in aimNd.ChildNodes)
    {
        ret[nd.Name] = nd.InnerText;
    }
    return ret;
}

/// <summary>
/// 返回有层级关系的子节点,子子节点下所有元素,递归深度=2.
/// 递归深度1:子节点
/// 递归深度2:每个子节点中的子节点
/// </summary>
/// <param name="doc"></param>
/// <param name="ss"></param>
/// <returns> Dictionary<string, Dictionary<string, string>> 按结构关系返回子节点,子子节点下的所有元素</returns>
public static Dictionary<string, Dictionary<string, string>> GetSub2DataInHierarchy(XmlDocument doc, params string[] ss)
{
    Dictionary<string, Dictionary<string, string>> ret = new Dictionary<string, Dictionary<string, string>>();
    //根节点
    XmlElement rootElement = doc.DocumentElement;
    XmlNode aimND = GetXmlNodeByNames(rootElement, ss);

    foreach (XmlNode nd in aimND.ChildNodes)
    {
        //第一次循环读取外层的名字(key)
        //string sub1Str = nd.Name;
        //新建一个字典容器(Value)
        Dictionary<string, string> sub2Dic = new Dictionary<string, string>();

        foreach (XmlNode nnd in nd.ChildNodes)
        {
            sub2Dic.Add(nnd.Name, nnd.InnerText);
        }
        ret.Add(nd.Name, sub2Dic);
    }
    return ret;
}

/// <summary>
/// 修改Xml值
/// </summary>
/// <param name="doc"></param>
/// <param name="value"></param>
/// <param name="ss"></param>
public static void SetXmlValueByKeys(XmlDocument doc, string value, params string[] ss)
{
    //根节点
    XmlElement rootElement = doc.DocumentElement;
    XmlNode cur = rootElement;
    foreach (string s in ss)
    {
        cur = GetXmlNodeByName(cur, s);
    }
    cur.InnerText = value;
}


//私有--------------------------------------------------------------------------------------------------------------------
private static XmlNode GetXmlNodeByName(XmlNode nd, string s)
{
    foreach (XmlNode nnd in nd.ChildNodes)
    {
        if (nnd.Name == s) 
        {
            return nnd;
        }
    }
    return null;
}
private static XmlNode GetXmlNodeByNames(XmlNode nd, string[] ss)
{
    XmlNode cur = nd;
    if (ss == null)
        return cur;

    foreach (string s in ss)
    {
        cur = GetXmlNodeByName(cur, s);
    }
    return cur;
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;


public class Assist
{
    //分割字符串函数
    public static List<string> SplitString(string str, string div)
    {
        List<string> ret = new List<string>();
        string[] ss = str.Split(div.ToCharArray());
        foreach(var v in ss)
        {
            if (v != "") 
            {
                ret.Add(v);
            }
        }
        return ret;
    }
}

到这里你会发现,当你向 “/菜单编辑.xml"文件中增加菜名和往”/菜单配图/"增加图片,如果添加错误我们为了方便设计了一个类,通过窗口弹窗的方式来提示错误。在这里插入图片描述
代码如图:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;
using System.Runtime.InteropServices;//调用外部库,需要引用命名空间


public class PopMessage
{
    [DllImport("User32.dll", SetLastError = true, ThrowOnUnmappableChar = true, CharSet = CharSet.Auto)]
    public static extern int MessageBox(IntPtr handle, String message, String title, int type);//具体方法
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值