9.生成二进制数据文件

9.Excel表自动生成相关文件-生成二进制数据文件


9.1 知识点

声明2进制数据存储位置路径和真正内容开始的行号

public static string DATA_BINARY_PATH = Application.streamingAssetsPath + "/Binary/";

public static int BEGIN_INDEX = 4;

创建生成excel2进制数据函数,在生成Excel信息的菜单项函数调用


[MenuItem("GameTool/GenerateExcel")]
private static void GenerateExcelInfo()
{
    ...
    //遍历文件中的所有表的信息
    foreach (DataTable table in tableConllection)
    {
        Debug.Log(table.TableName);
        //生成数据结构类
        GenerateExcelDataClass(table);
        //生成容器类
        GenerateExcelContainer(table);
        //生成2进制数据
        GenerateExcelBinary(table);
    }
}
    

/// <summary>
/// 生成excel2进制数据
/// </summary>
/// <param name="table"></param>
private static void GenerateExcelBinary(DataTable table)
{

}

检查二进制路径是否存在,如果不存在则创建二进制路径。创建一个二进制文件进行写入,文件名由表格的名称和后缀组成。写入数据行数(减去4是因为前面4行是配置规则,不是需要记录的数据内容)。存储主键变量名,将字符串转换为字节数组,并写入字节数组的长度和内容。遍历所有数据行,获取每一行的数据。获取类型行,根据类型来决定如何写入数据。根据类型进行相应的写入操作:如果是整数类型,将整数值转换为字节数组,并写入4个字节。如果是浮点数类型,将浮点数值转换为字节数组,并写入4个字节。如果是布尔类型,将布尔值转换为字节数组,并写入1个字节。如果是字符串类型,将字符串转换为字节数组,并依次写入字节数组的长度和内容。关闭文件流。刷新项目窗口。

private static void GenerateExcelBinary(DataTable table)
{
    // 检查路径是否存在,不存在则创建路径
    if (!Directory.Exists(DATA_BINARY_PATH))
        Directory.CreateDirectory(DATA_BINARY_PATH);

    // 创建一个二进制文件进行写入
    using (FileStream fs = new FileStream(DATA_BINARY_PATH + table.TableName + ".tao", FileMode.OpenOrCreate, FileAccess.Write))
    {
        // 存储具体的excel对应的二进制信息

        // 1. 先存储数据行数,方便读取
        // -4 的原因是前面4行是配置规则,不是我们需要记录的数据内容
        fs.Write(BitConverter.GetBytes(table.Rows.Count - 4), 0, 4);

        // 2. 存储主键变量名
        string keyName = GetVariableNameRow(table)[GetKeyIndex(table)].ToString();//id
        byte[] bytes = Encoding.UTF8.GetBytes(keyName);
        // 存储字符串字节数组的长度
        fs.Write(BitConverter.GetBytes(bytes.Length), 0, 4);
        // 存储字符串字节数组
        fs.Write(bytes, 0, bytes.Length);

        // 遍历所有内容的行进行二进制写入
        DataRow row;
        // 得到类型行,根据类型来决定如何写入数据
        DataRow rowType = GetVariableTypeRow(table);
        for (int i = BEGIN_INDEX; i < table.Rows.Count; i++)
        {
            // 得到一行的数据
            row = table.Rows[i];
            for (int j = 0; j < table.Columns.Count; j++)
            {
                switch (rowType[j].ToString())
                {
                    case "int":
                        fs.Write(BitConverter.GetBytes(int.Parse(row[j].ToString())), 0, 4);
                        break;
                    case "float":
                        fs.Write(BitConverter.GetBytes(float.Parse(row[j].ToString())), 0, 4);
                        break;
                    case "bool":
                        fs.Write(BitConverter.GetBytes(bool.Parse(row[j].ToString())), 0, 1);
                        break;
                    case "string":
                        bytes = Encoding.UTF8.GetBytes(row[j].ToString());
                        // 写入字符串字节数组的长度
                        fs.Write(BitConverter.GetBytes(bytes.Length), 0, 4);
                        // 写入字符串字节数组
                        fs.Write(bytes, 0, bytes.Length);
                        break;
                }
            }
        }

        fs.Close();
    }

    // 刷新Project窗口
    AssetDatabase.Refresh();
}

查看二进制数据文件是否生成成功


9.2 知识点代码

using Excel;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.IO;
using System.Text;
using UnityEditor;
using UnityEngine;

public class ExcelTool
{
    /// <summary>
    /// excel文件存放的路径
    /// </summary>
    public static string EXCEL_PATH = Application.dataPath + "/ArtRes/Excel/";

    /// <summary>
    /// 数据结构类脚本存储位置路径
    /// </summary>
    public static string DATA_CLASS_PATH = Application.dataPath + "/Scripts/ExcelData/DataClass/";

    /// <summary>
    /// 容器类脚本存储位置路径
    /// </summary>
    public static string DATA_CONTAINER_PATH = Application.dataPath + "/Scripts/ExcelData/Container/";

    /// <summary>
    /// 真正内容开始的行号
    /// </summary>
    public static int BEGIN_INDEX = 4;

    [MenuItem("GameTool/GenerateExcel")]
    private static void GenerateExcelInfo()
    {
        //加载指定路径中的所有Excel文件 用于生成对应的3个文件
        DirectoryInfo dInfo = Directory.CreateDirectory(EXCEL_PATH);
        //得到指定路径中的所有文件信息 相当于就是得到所有的Excel表
        FileInfo[] files = dInfo.GetFiles();
        //数据表容器
        DataTableCollection tableConllection;
        for (int i = 0; i < files.Length; i++)
        {
            //如果不是excel文件就不要处理了
            if (files[i].Extension != ".xlsx" &&
                files[i].Extension != ".xls")
                continue;
            //打开一个Excel文件得到其中的所有表的数据
            using (FileStream fs = files[i].Open(FileMode.Open, FileAccess.Read))
            {
                IExcelDataReader excelReader = ExcelReaderFactory.CreateOpenXmlReader(fs);
                tableConllection = excelReader.AsDataSet().Tables;
                fs.Close();
            }

            //遍历文件中的所有表的信息
            foreach (DataTable table in tableConllection)
            {
                //生成数据结构类
                GenerateExcelDataClass(table);
                //生成容器类
                GenerateExcelContainer(table);
                //生成2进制数据
                GenerateExcelBinary(table);
            }

        }
    }

    /// <summary>
    /// 生成Excel表对应的数据结构类
    /// </summary>
    /// <param name="table"></param>
    private static void GenerateExcelDataClass(DataTable table)
    {
        //字段名行
        DataRow rowName = GetVariableNameRow(table);
        //字段类型行
        DataRow rowType = GetVariableTypeRow(table);

        //判断路径是否存在 没有的话 就创建文件夹
        if (!Directory.Exists(DATA_CLASS_PATH))
            Directory.CreateDirectory(DATA_CLASS_PATH);
        //如果我们要生成对应的数据结构类脚本 其实就是通过代码进行字符串拼接 然后存进文件就行了
        string str = "public class " + table.TableName + "\n{\n";

        //变量进行字符串拼接
        for (int i = 0; i < table.Columns.Count; i++)
        {
            str += "    public " + rowType[i].ToString() + " " + rowName[i].ToString() + ";\n";
        }

        str += "}";

        //把拼接好的字符串存到指定文件中去
        File.WriteAllText(DATA_CLASS_PATH + table.TableName + ".cs", str);

        //刷新Project窗口
        AssetDatabase.Refresh();
    }

    /// <summary>
    /// 生成Excel表对应的数据容器类
    /// </summary>
    /// <param name="table"></param>
    private static void GenerateExcelContainer(DataTable table)
    {
        //得到主键索引
        int keyIndex = GetKeyIndex(table);
        //得到字段类型行
        DataRow rowType = GetVariableTypeRow(table);
        //没有路径创建路径
        if (!Directory.Exists(DATA_CONTAINER_PATH))
            Directory.CreateDirectory(DATA_CONTAINER_PATH);

        string str = "using System.Collections.Generic;\n";

        str += "public class " + table.TableName + "Container" + "\n{\n";

        str += "    ";
        str += "public Dictionary<" + rowType[keyIndex].ToString() + ", " + table.TableName + ">";
        str += "dataDic = new " + "Dictionary<" + rowType[keyIndex].ToString() + ", " + table.TableName + ">();\n";

        str += "}";

        File.WriteAllText(DATA_CONTAINER_PATH + table.TableName + "Container.cs", str);

        //刷新Project窗口
        AssetDatabase.Refresh();
    }


    /// <summary>
    /// 生成excel2进制数据
    /// </summary>
    /// <param name="table"></param>
    private static void GenerateExcelBinary(DataTable table)
    {
        //没有路径创建路径
        if (!Directory.Exists(BinaryDataMgr.DATA_BINARY_PATH))
            Directory.CreateDirectory(BinaryDataMgr.DATA_BINARY_PATH);

        //创建一个2进制文件进行写入
        using (FileStream fs = new FileStream(BinaryDataMgr.DATA_BINARY_PATH + table.TableName + ".tao", FileMode.OpenOrCreate, FileAccess.Write))
        {
            //存储具体的excel对应的2进制信息
            //1.先要存储我们需要写多少行的数据 方便我们读取
            //-4的原因是因为 前面4行是配置规则 并不是我们需要记录的数据内容
            fs.Write(BitConverter.GetBytes(table.Rows.Count - 4), 0, 4);
            //2.存储主键的变量名
            string keyName = GetVariableNameRow(table)[GetKeyIndex(table)].ToString();
            byte[] bytes = Encoding.UTF8.GetBytes(keyName);
            //存储字符串字节数组的长度 一个int型4个字节
            fs.Write(BitConverter.GetBytes(bytes.Length), 0, 4);
            //存储字符串字节数组
            fs.Write(bytes, 0, bytes.Length);

            //遍历所有内容的行 进行2进制的写入
            DataRow row;
            //得到类型行 根据类型来决定应该如何写入数据
            DataRow rowType = GetVariableTypeRow(table);
            for (int i = BEGIN_INDEX; i < table.Rows.Count; i++)
            {
                //得到一行的数据
                row = table.Rows[i];
                for (int j = 0; j < table.Columns.Count; j++)
                {
                    switch (rowType[j].ToString())
                    {
                        case "int":
                            fs.Write(BitConverter.GetBytes(int.Parse(row[j].ToString())), 0, 4);
                            break;
                        case "float":
                            fs.Write(BitConverter.GetBytes(float.Parse(row[j].ToString())), 0, 4);
                            break;
                        case "bool":
                            fs.Write(BitConverter.GetBytes(bool.Parse(row[j].ToString())), 0, 1);
                            break;
                        case "string":
                            bytes = Encoding.UTF8.GetBytes(row[j].ToString());
                            //写入字符串字节数组的长度
                            fs.Write(BitConverter.GetBytes(bytes.Length), 0, 4);
                            //写入字符串字节数组
                            fs.Write(bytes, 0, bytes.Length);
                            break;
                    }
                }
            }

            fs.Close();
        }

        AssetDatabase.Refresh();
    }

    /// <summary>
    /// 获取变量名所在行
    /// </summary>
    /// <param name="table"></param>
    /// <returns></returns>
    private static DataRow GetVariableNameRow(DataTable table)
    {
        return table.Rows[0];
    }

    /// <summary>
    /// 获取变量类型所在行
    /// </summary>
    /// <param name="table"></param>
    /// <returns></returns>
    private static DataRow GetVariableTypeRow(DataTable table)
    {
        return table.Rows[1];
    }

    
    /// <summary>
    /// 获取主键索引
    /// </summary>
    /// <param name="table"></param>
    /// <returns></returns>
    private static int GetKeyIndex(DataTable table)
    {
        DataRow row = table.Rows[2];
        for (int i = 0; i < table.Columns.Count; i++)
        {
            if (row[i].ToString() == "key")
                return i;
        }
        return 0;
    }
}


转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 785293209@qq.com

×

喜欢就点赞,疼爱就打赏