UD2SL1——XML序列化

本章代码关键字

1
2
3
4
5
6
7
8
9
using () { }                        //用于方便流对象释放和销毁,当大括号的代码块执行完毕时,会自动销毁释放括号内实例化的对象
StreamWriter //用于存储文件的文件流
XmlSerializer //用于序列化对象为xml的关键类
xmlSerializer.Serialize(, ) //第一个参数填文件流,第二个文件填构造时传入的类型的实例化对象,将该实例化对象序列化
[XmlElement("testPublic123123")] //该特性可以修改存储到xml的名字
[XmlArray("IntList")] //对于数组,列表,该特性可以修改列表本身存储到xml的名字
[XmlArrayItem("Int32")] //对于数组,列表,该特性可以修改列表成员存储到xml的名字
[XmlAttribute("Test1")] //该特性将元素节点改为属性,若填入参数还会改名
[XmlAttribute()] //不填参数不会改名

何为序列化和反序列化

序列化

把对象转化为可传输的字节序列过程称为序列化
简单来说就是:把想要存储的内容转换为字节序列用于存储或传递

反序列化

把字节序列还原为对象的过程称为反序列化
简单来说就是:把存储或收到的字节序列信息解析读取出来使用

XML序列化

序列化流程

  1. 有一个想要保存的类对象
  2. 使用 XmlSerializer​ 序列化该对象
  3. 通过 StreamWriter​ 配合 using​将数据存储 写入文件

注意:

  1. 只能序列化公共成员

  2. 不支持字典序列化

  3. 可以通过特性修改节点信息 或者设置属性信息

  4. Stream​相关要配合using​使用

  5. 注意!类中引用类型变量如果为null,则序列化时不会为该变量创建节点

  6. 注意!要序列化的类的列表变量不可以初始化!!!因为反序列化时不会覆盖而是增加,这会造成数据重复!!!

  7. 准备一个数据结构类

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    public class Lesson1Test
    {
    public int testPublic = 10;
    private int testPrivate = 11;
    protected int testProtected = 12;
    internal int testInternal = 13;

    public string testPublicStr = "123";

    public int testPro { get; set; }

    public Lesson1Test2 testClass = new Lesson1Test2();
    }

    public class Lesson1Test2
    {
    public int test1 = 1;
    public float test2 = 1.1f;
    public bool test3 = true;
    }

    Lesson1Test lt = new Lesson1Test();
  8. 进行序列化

    关键知识点:

    • ​XmlSerializer​ 用于序列化对象为xml的关键类
    • ​StreamWriter​ 用于存储文件
    • ​using​ 用于方便流对象释放和销毁

    序列化步骤

    1. 第一步:确定存储路径

      1
      2
      //第一步:确定存储路径
      string path = Application.persistentDataPath + "/Lesson1Test.xml";
    2. 第二步:结合 using​ 知识点 和 StreamWriter​ 这个流对象 来写入文件

    3. 第三步:进行XML文件序列化

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      //第二步:结合 using 知识点 和 StreamWriter 这个流对象 来写入文件
      using (StreamWriter stream = new StreamWriter(path))
      {
      //第三步:进行XML文件序列化
      XmlSerializer s = new XmlSerializer(typeof(Lesson1Test));
      //这句代码的含义 就是通过序列化对象 对我们的类对象进行翻译 将其翻译成我们的xml文件 写入到对象的文件中
      //第一个参数:文件流对象
      //第二个参数:想要被翻译的对象
      //注意!用于翻译(序列化为xml)的对象在构造时传入构造函数的类型 一定要和接下来翻译要传入的对象类型是一致的 不然会报错!!!
      s.Serialize(stream, lt);
      }

    存储结果如下:
    分析储存结果可以发现:私有的,保护的,内联的成员变量都没有存储,也就是说只能序列化公共成员

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    <?xml version="1.0" encoding="utf-8"?>
    <Lesson1Test xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <testPublic>10</testPublic>
    <testPublicStr>123</testPublicStr>
    <testClass>
    <test1>1</test1>
    <test2>1.1</test2>
    <test3>true</test3>
    </testClass>
    <testPro>0</testPro>
    </Lesson1Test>

XmlSerializer 用于序列化对象为xml的关键类

通过序列化对象 对我们的类对象进行翻译 将其翻译成我们的xml文件 写入到对象的文件中
实例化时要传入 将要被序列化的对象 的类型,实例化出来的对象就能且仅能对该类型进行序列化
就像是翻译机器一样
使用xmlSerializer.Serialize()​来完成序列化
下面代码的含义 就是通过序列化对象 对我们的类对象进行翻译 将其翻译成我们的xml文件 写入到对象的文件中
第一个参数:文件流对象
第二个参数:想要被翻译的对象
注意!用于翻译(序列化为xml)的对象在构造时传入构造函数的类型 一定要和接下来翻译要传入的对象类型是一致的 不然会报错!!!

1
2
3
4
5
6
7
Lesson1Test lt = new Lesson1Test();
string path = Application.persistentDataPath + "/Lesson1Test.xml";
using (StreamWriter stream = new StreamWriter(path))
{
XmlSerializer s = new XmlSerializer(typeof(Lesson1Test));
s.Serialize(stream, lt);
}

StreamWriter 用于存储文件

传入路径,实例化一个文件流 如果有该文件 直接打开并修改 如果没有该文件 直接新建一个文件
之后就会对该文件进行修改等操作,配合using​和XmlSerializer​使用

using 用于方便流对象释放和销毁

using​​ 的新用法:
在之前using​​是用来引用命名空间的
而这里的using​​,会使括号当中包裹的声明的对象,在大括号语句块结束后 自动释放掉
或者说 当语句块结束 会自动帮我们调用 对象的 Dispose​ ** 这个方法 让其进行销毁**
using​​ 一般都是配合 内存占用较大 或者有读写操作时 进行使用的(以防出现问题)
简单来说,一般读写的对象都会配合它来使用

1
using (StreamWriter stream = new StreamWriter(path)) { }

能否存储更多的类型?

运行下面的代码,可以发现序列化支持数组,列表的序列化,但不支持字典的序列化,强行序列化会报错!!! 注意!要序列化的类的列表变量不可以初始化!!!因为反序列化时不会覆盖而是增加,这会造成数据重复!!!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
public class Lesson1Test
{
public int testPublic = 10;
private int testPrivate = 11;
protected int testProtected = 12;
internal int testInternal = 13;

public string testPublicStr = "123";

public int testPro { get; set; }

public Lesson1Test2 testClass = new Lesson1Test2();

public int[] arrayInt = new int[3] { 5, 6, 7 };
public List<int> listInt; //= new List<int>() { 1, 2, 3, 4 };切勿在类里直接初始化,因为序列化读取时不会覆盖而是增加,会直接导致数据重复!
public List<Lesson1Test2> listItem = new List<Lesson1Test2>() { new Lesson1Test2(), new Lesson1Test2() };
//这种序列化是不支持字典的!!!
//public Dictionary<int, string> testdic = new Dictionary<int, string>() { { 1, "123" } };
}

public class Lesson1Test2
{
public int test1 = 1;
public float test2 = 1.1f;
public bool test3 = true;
}

public class Lesson1 : MonoBehaviour
{
void Start()
{
Lesson1Test lt = new Lesson1Test();
string path = Application.persistentDataPath + "/Lesson1Test.xml";
using (StreamWriter stream = new StreamWriter(path))
{
XmlSerializer s = new XmlSerializer(typeof(Lesson1Test));
s.Serialize(stream, lt);
}
}
}

自定义节点名 或 设置属性

可以通过特性 设置节点或者设置属性,并且修改名字

1
2
3
4
5
[XmlElement("testPublic123123")]    //该特性可以修改存储到xml的名字
[XmlArray("IntList")] //对于数组,列表,该特性可以修改列表本身存储到xml的名字
[XmlArrayItem("Int32")] //对于数组,列表,该特性可以修改列表成员存储到xml的名字
[XmlAttribute("Test1")] //该特性将元素节点改为属性,若填入参数还会改名
[XmlAttribute()] //不填参数不会改名
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
public class Lesson1Test
{
[XmlElement("testPublic123123")] //该特性可以修改存储到xml的名字
public int testPublic = 10;
private int testPrivate = 11;
protected int testProtected = 12;
internal int testInternal = 13;

public string testPublicStr = "123";

public int testPro { get; set; }

public Lesson1Test2 testClass = new Lesson1Test2();

public int[] arrayInt = new int[3] { 5, 6, 7 };
[XmlArray("IntList")] //对于数组,列表,该特性可以修改列表本身存储到xml的名字
[XmlArrayItem("Int32")] //对于数组,列表,该特性可以修改列表成员存储到xml的名字
public List<int> listInt //= new List<int>() { 1, 2, 3, 4 };切勿在类里直接初始化,因为序列化读取时不会覆盖而是增加,会直接导致数据重复!
public List<Lesson1Test2> listItem = new List<Lesson1Test2>() { new Lesson1Test2(), new Lesson1Test2() };
}

public class Lesson1Test2
{
[XmlAttribute("Test1")] //该特性将元素节点改为属性,若填入参数还会改名
public int test1 = 1;
[XmlAttribute()] //不填参数不会改名
public float test2 = 1.1f;
[XmlAttribute()]
public bool test3 = true;
}

运行结果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<?xml version="1.0" encoding="utf-8"?>
<Lesson1Test xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<testPublic123123>10</testPublic123123>
<testPublicStr>123</testPublicStr>
<testClass Test1="1" test2="1.1" test3="true" />
<arrayInt>
<int>5</int>
<int>6</int>
<int>7</int>
</arrayInt>
<IntList>
<Int32>1</Int32>
<Int32>2</Int32>
<Int32>3</Int32>
<Int32>4</Int32>
</IntList>
<listItem>
<Lesson1Test2 Test1="1" test2="1.1" test3="true" />
<Lesson1Test2 Test1="1" test2="1.1" test3="true" />
</listItem>
<testPro>0</testPro>
</Lesson1Test>