Unity数据持久化笔记

XML

XML相关类:

XmlNode、XmlDocument、XmlDeclaration、XmlElement。

后面的类都继承自第一个。

基本操作

新建Xml类:

XmlDocument xmlDocument = new XmlDocument();

读取Xml文件:

xmlDocument.Load(path);

读取节点:(相当于找到一个<XXX></XXX>)

XmlNode xmlNode= xmlDocument.SelectSingleNode(key);

xmlNode也可以执行SelectSingleNode(key);

读取节点内容:(相当于找到一个<XXX></XXX>中间的内容)

xmlNode.InnerText;

读取一组同名节点:

XmlNodeList xmlNodeList=xmlNode.SelectNodes(key);

读取节点属性:

xmlNode.Attributes[key].Value;

声明版本和编码方式:

XmlDeclaration xmlDeclaration=xmlDocument.CreateXmlDeclaration
        ("1.0","UTF-8","");

创建节点:(相当于创建一个<XXX></XXX>)

XmlElement xmlElement=xmlDocument.CreateElement(key);

写入节点值:

xmlElement.InnerText=value;

追加节点(包括追加xmlDeclaration):

追加根节点:(不执行这一步相当于前面的创建白写)

xmlDocument.AppendChild(xmlNode);

追加子节点(最后必须追加到xmlDocument才有效):

xmlNode1.AppendChild(xmlNode2);

写入节点属性:

xmlElement.SetAttribute(key,value);

保存:

xmlDocument.Save(path);

Xml序列化反序列化

序列化

using System.IO;
using System.Xml.Serialization;

using(StreamWriter streamWriter = new StreamWriter(path, false)){
    XmlSerializer xmlSerializer = new XmlSerializer(data.GetType());
    xmlSerializer.Serialize(streamWriter,data);
}

反序列化

using System.IO;
using System.Xml.Serialization;
using System;

if(File.Exists(path)){
    using(StreamReader streamReader = new StreamReader(path)){
        XmlSerializer xmlSerializer = new XmlSerializer(type);
        return xmlSerializer.Deserialize(streamReader);
    }
}
else{
    return Activator.CreateInstance(type);
}

反序列化读不出来

数据结构:

[Serializable]
    public class PlaneData{
        [XmlAttribute]
        public int hp;
        [XmlAttribute]
        public int speed;
        [XmlAttribute]
        public int volume;
        [XmlAttribute]
        public string path;
        [XmlAttribute]
        public float scale;
    }
    [Serializable]
    public class AllPlaneData{
        public List<PlaneData> planeDatas=new List<PlaneData>();
    }

Xml:

<?xml version="1.0" encoding="utf-8"?>
<AllPlaneData xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <planeDatas>
  	<PlaneData hp="8" speed="8" volume="4" path="飞机大战/Airplane1" scale="1"/>
  	<PlaneData hp="9" speed="7" volume="4" path="飞机大战/Airplane2" scale="1"/>
  	<PlaneData hp="6" speed="10" volume="4" path="飞机大战/Airplane3" scale="1"/>
  	<PlaneData hp="10" speed="5" volume="4" path="飞机大战/Airplane4" scale="0.6"/>
  	<PlaneData hp="7" speed="9" volume="4" path="飞机大战/Airplane5" scale="1"/>
  </planeDatas>
</AllPlaneData>

把数据结构写入Xml一份,和自己写的对比;又把自己写的内容复制进程序写的xml,能读出来;又把读取的代码改成读取程序写入的Application.persistentDataPath下的文件,能读出来。好像是Application.streamingAssetsPath路径出了问题。发现确实是程序里的文件名Plane打成了Plan。之前我在反序列化程序里判断文件是否存在后面打印,打印出来了,那个其实是其他数据的反序列化打印的。

改进:编辑器里找不到xml文件时打印一个提示。

public object XmlDeserialize(Type type,string path){
        if(File.Exists(path)){
            using(StreamReader streamReader = new StreamReader(path)){
                XmlSerializer xmlSerializer = new XmlSerializer(type);
                return xmlSerializer.Deserialize(streamReader);
                 
            }
        }
        #if UNITY_EDITOR
        Debug.Log(path+"没有找到!!!!!!!!!!!!!!!!!!");
        #endif
        return Activator.CreateInstance(type);
    }

JSON

用于JSON序列化的类必须添加[Serializable]特性

[Serializable]
    public class ServerInfo{
        public int id;
        public string name;
        public int serverStatus;
    }

一个某种基类Base组成的List,里面的元素由它和它的各种子类组成,能序列化成json吗?

用LitJson可以:

[Serializable]
public class ItemJson{
     public int id;
}
[Serializable]
public class MagJson:ItemJson{
    public int ammo;
}
public class JsonTest:MonoBehaviour{
    public List<ItemJson> items;
    [ContextMenu("打印json")]
    void PrintJson(){
        items=new List<ItemJson>(){
            new ItemJson(){
                id = 0
            },
            new MagJson(){
                id=1,
                ammo=30
            }
        };
        Debug.Log(JsonMapper.ToJson(items));
    }
}

但是在检查器面板上只能显示基类的字段。

所以可以把一个背包,里面装有弹匣、药品、饮料、手榴弹等不同属性的类的List转换成Json持久存储。问题在于反序列化时,API不能识别出一个元素是哪个子类,只能全部当成基类读出,导致子类多的数据全部丢失。

枚举序列化会变成什么

[ContextMenu("枚举序列化")]
    void PrintEnum(){
        string jsonString=JsonUtility.ToJson(itemA1);
        Debug.Log(jsonString);
    }
    public ItemA itemA1;
}
public enum ItemType{
        Medicine,Grenade,Other
    }
[Serializable]
    public class ItemA{
        public ItemType itemType;
        public int id;
        public int num;
    }

二进制

二进制序列化有几个特点:

  1. 序列化的结果人看不懂,需要序列化后反序列化能把数据还原才能确定没问题。
  2. 长度可变的数据类型:字符串、列表需要先记一个长度;

序列化是写一个支持任意类的(泛用)还是每个类写一个(专用)?

写专用序列化方法时,一个个字段写BitConverter.GetBytes(),然后增加偏移量感觉很笨,但是手写泛用序列化方法,需要处理嵌套类、列表、自定义类的列表,难度较大。

C#自带的BinaryFormatter可以序列化任意类,不过据说已经过时。

public void Save(object obj,string fileName){
        if(!Directory.Exists(path)){
            Directory.CreateDirectory(path);
        }
        using(FileStream fileStream=new FileStream(path+fileName, 
        FileMode.OpenOrCreate,FileAccess.Write)){
            BinaryFormatter binaryFormatter=new BinaryFormatter();
            binaryFormatter.Serialize(fileStream,obj);
            fileStream.Close();
        }
    }
    public T Load<T>(string fileName)where T:class{
        if(!File.Exists(path+fileName)){
            return default(T);
        }
        T obj;
        using(FileStream fileStream=new FileStream(path+fileName, 
        FileMode.OpenOrCreate,FileAccess.Read)){
            BinaryFormatter binaryFormatter= new BinaryFormatter();
            obj=binaryFormatter.Deserialize(fileStream) as T;
            fileStream.Close();
        }
        return obj;
    }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值