Unity数据持久化之二进制(之二)

我们在上一个文章中提到了,在C#中使用代码操作文件,我们接下来再看看在C#中如何使用代码操作文件夹。C#提供了一个文件夹操作公共类Directory,其中给我们提供了一些操作文件夹的方法。

Directory中的方法

1.判断文件夹是否存在

2.创建文件夹

代码如下,如果存在文件夹则打印"存在文件夹",否则就打印“不存在文件夹”并创建文件夹

        if (Directory.Exists(Application.dataPath + "/DataPersistance"))
        {
            print("存在文件夹");
        }
        else
        {
            print("文件夹不存在");
            //2.创建文件夹
            DirectoryInfo info = Directory.CreateDirectory(Application.dataPath + "/DataPersistance");
        }

3.删除文件夹

        //3.删除文件夹   
        //参数一:路径
        //参数二:是否删除非空目录,如果为true,将删除整个目录,如果是false,仅当改目录为空时才可以删除
        /Directory.Delete(Application.dataPath + "/DataPersistance");

4.查找指定文件夹和指定文件

        //得到指定路径下的所有文件夹名
        string[] strs = Directory.GetDirectories(Application.dataPath);
        for (int i = 0; i < strs.Length; i++)
        {
            print(strs[i]);   
        }

        //得到指定路径下的所有文件名
        strs = Directory.GetFiles(Application.dataPath);
        for (int i = 0; i < strs.Length; i++)
        {
            print(strs[i]);
        }

 5.移动文件夹(第一个参数为原文件路径,第二个参数为目标文件路径)

        //5.移动文件夹
        //如果第二个参数所在的路径已经存在了一个文件夹 就会报错
        //移动会把文件夹中的所有内容 一起移动到新的路径
        Directory.Move(Application.dataPath + "/DataPersistance", Application.dataPath+"/moveFile");

上述就是Directory中提供的常用的方法,在此基础上我们还可以通过DirectoryInfo获取到文件夹的更多信息

DirectoryInfo目录信息类和FileInfo文件信息类

        //DirectoryInfo目录信息类
        //我们可以通过它获取文件夹的更多信息
        //它主要出现在两个地方
        //1.创建文件夹方法的返回值
        DirectoryInfo dInfo = Directory.CreateDirectory(Application.dataPath + "/DataPersistance2");
        print("**********************");
        //全路径
        print(dInfo.FullName);
        //文件名
        print(dInfo.Name);

        //2.查找上级文件夹信息
        dInfo = Directory.GetParent(Application.dataPath + "/DataPersistance2");
        print("**********************");
        //全路径
        print(dInfo.FullName);
        //文件名
        print(dInfo.Name);

        //重要方法 
        //得到所有文件夹的目录信息
        FileInfo[] fInfos = dInfo.GetFiles();
        for (int i = 0; i <fInfos.Length; i++)
        {
            print(fInfos[i].Name);//文件名
            print(fInfos[i].FullName);//路径
            print(fInfos[i].Length);//字节长度
            print(fInfos[i].Extension);//后缀名

            //返回一个文件流
            //fInfos[i].Open() 
        }

了解完了上述字节码转换,文件文件夹操作、数据的流的相关使用后,我们可以尝试去序列化对象。 我们先声明一些需要序列化的数据类型例子。

类对象的序列化

两个类型(一个Person一个ClassTesr)一个结构体类型(StructTest)

        [System.Serializable]
    public class Person
    {
        public int age = 1;
        public string name = "mqx";
        public int[] ints = new int[] { 1, 2, 3, 4, 5 };
        public List<int> list = new List<int>() { 1, 2, 3, 4, 5 };
        public Dictionary<int, string> dic = new Dictionary<int, string>() { { 1, "NO.1" }, { 2, "NO.2" }, { 3, "NO.3" } };
        public StructTest st = new StructTest(2, "123");
        public ClassTest ct = new ClassTest();
    }
    [System.Serializable]
    public struct StructTest {
        public int i;
        public string s;
        public StructTest(int i,string s)
        {
            this.i = i;
            this.s = s;
        }
    }
    [System.Serializable]
    public class ClassTest {
        public int i = 1;
    }

 有两种方法可以去序列化Person类实例的方法,文件流存储和内存流存储:

方法一:使用内存流得到二进制字节数组

        using (MemoryStream ms = new MemoryStream())
        {
            //二进制格式化程序
            BinaryFormatter bf = new BinaryFormatter();
            //生产二进制字节数组 写入到内存流中
            bf.Serialize(ms, person);
            //得到对象的二进制字节数组
            byte[] bytes = ms.GetBuffer();
            //存储字节
            File.WriteAllBytes(Application.dataPath + "/Lesson5.mqx", bytes);
            ms.Close();
            //关闭内存流下
        }

其本质就是通过BinaryFormatter去将对象转为二进制格式,写入内存流中,然后又从内存流中获取到这个二进制字数组,最后通过File写入文件。关闭内存流。

方法二:使用文件流进行存储

            using (FileStream fs = new FileStream(Application.dataPath+"/Lesson5_2",FileMode.OpenOrCreate,FileAccess.Write)) { 
            BinaryFormatter bf = new BinaryFormatter();
            bf.Serialize(fs, person);
            fs.Flush();
            fs.Close();
        }

这个方法的本质同样需要使用到BinaryFormatter将二进制进行转换,然后直接通过FileStream文件流写入文件,最后关闭文件流。

然后再是反序列化,反序列化其本质核心与序列化相同,都基本使用BinaryFormatter类和FileStream类(由于Unity网络开发还没有接触)所以还是使用MemoryStream内存流读取数据。

类对象的反序列化:

        #region 反序列化之 反序列化文件中的数据
        //主要类
        //FileStream文件流
        //BinaryFormatter
        //主要方法
        //Deserizlize
        using (FileStream fs = File.Open(Application.dataPath + "/Lesson5_2", FileMode.Open, FileAccess.ReadWrite)) {
            BinaryFormatter bf = new BinaryFormatter();
            Lesson5.Person p= bf.Deserialize(fs) as Lesson5.Person;
        }
        #endregion

        #region 反序列之反序列化网络传输过来二进制数据
        //主要类 
        //MemoryStream内存流类
        //BinaryFormatter 二进制格式化类
        //主要方法
        //Deserizlize
        //目前没有网络传输就直接从文件获取
        byte[] bytes = File.ReadAllBytes(Application.dataPath + "/Lesson5_2.mqx");

        //声明内存流对象 一开始就把字节流数组传输进去
        using (MemoryStream ms=new MemoryStream (bytes)) {
            BinaryFormatter bf = new BinaryFormatter();
            Lesson5.Person p= bf.Deserialize(ms) as Lesson5.Person;
            ms.Close();
        }
        #endregion
    }

其本质是声明一个对象流或者文件流,将需要序反序列化的文件传入BinaryForamatter对象中,然后将返回值as成相同类型。

学习了对象序列化和反序列化的基础操作后,可以尝试写一个用于此操作的单例类,代码如下

序列化单列类

    public class BinaryDataMgr
{
    private static BinaryDataMgr instance = new BinaryDataMgr();
    public static BinaryDataMgr Instance => instance;
    private BinaryDataMgr() { }

    private static string SAVE_PATH = Application.persistentDataPath + "/Data/";

    /// <summary>
    /// 存储类对象数据
    /// </summary>
    /// <param name="data">需要存储的对象</param>
    /// <param name="fileName">文件名</param>
    public void Save(object data,string fileName) {
        //判断路径文件夹是否存在
        if (Directory.Exists(SAVE_PATH))
        {
            Directory.CreateDirectory(SAVE_PATH);
        }
        using (FileStream fs = new FileStream(SAVE_PATH+fileName+".mqx",FileMode.OpenOrCreate,FileAccess.Write)) {
            BinaryFormatter bf = new BinaryFormatter();
            bf.Serialize(fs, data);
            fs.Close();
        }
    }

    /// <summary>
    /// 读取二进制数据转换为类对象
    /// </summary>
    /// <typeparam name="T">对象类型</typeparam>
    /// <param name="fileName">文件名</param>
    /// <returns></returns>
    public T Load<T>(string fileName) where T:class {
        if (!File.Exists(SAVE_PATH+fileName+".mqx"))
        {
            return default(T);
        }
        T obj;
        using (FileStream fs=File.Open(SAVE_PATH+fileName +".mqx",FileMode.Open,FileAccess.Read)) {
            BinaryFormatter bf = new BinaryFormatter();
            obj = bf.Deserialize(fs) as T;
            fs.Close();
        }
        return obj;
    }
}

猜你喜欢

转载自blog.csdn.net/qq_52690206/article/details/127791518