2023-05-29 Unity 2进制5——Excel配置表工具

2023-11-18

一、Excel 读取操作

(一)打开 Excel 表

  • IExcelDataReader:从流中读取 Excel 数据
  • DataSet:数据集合类,存储 Excel 数据
using Excel; // 引入命名空间

private static void OpenExcel() {
    using (FileStream fs = File.Open(Application.dataPath + "/ArtRes/Excel/PlayerInfo.xlsx", FileMode.Open, FileAccess.Read)) {
        // 传入excel表的文件流获取数据
        IExcelDataReader excelReader = ExcelReaderFactory.CreateOpenXmlReader(fs);
        // 将excel表中的数据转换为DataSet数据类型 
        DataSet result = excelReader.AsDataSet();
        // 得到Excel文件中的所有表信息
        for (int i = 0; i < result.Tables.Count; i++) {
            Debug.Log("表名:" + result.Tables[i].TableName);
            Debug.Log("行数:" + result.Tables[i].Rows.Count);
            Debug.Log("列数:" + result.Tables[i].Columns.Count);
        }

        fs.Close();
    }
}

(二)获取单元格信息

  • DataTable:数据表类,表示 Excel 文件中的一个表
  • DataRow:数据行类,表示某张表中的一行数据
private static void ReadExcel() {
    using (FileStream fs = File.Open(Application.dataPath + "/ArtRes/Excel/PlayerInfo.xlsx", FileMode.Open, FileAccess.Read)) {
        IExcelDataReader excelReader = ExcelReaderFactory.CreateOpenXmlReader(fs);
        DataSet result = excelReader.AsDataSet();

        for (int i = 0; i < result.Tables.Count; i++) {
            // 得到其中一张表的具体数据
            DataTable table = result.Tables[i];
            // 得到其中一行的数据
            // DataRow row = table.Rows[0];
            // 得到行中某一列的信息
            // Debug.Log(row[1].ToString());
            DataRow row;
            for (int j = 0; j < table.Rows.Count; j++) {
                // 得到每一行的信息
                row = table.Rows[j];
                Debug.Log("*********新的一行************");
                for (int k = 0; k < table.Columns.Count; k++) {
                    Debug.Log(row[k].ToString());
                }
            }
        }

        fs.Close();
    }
}

二、Excel 表配置工具

(一)基础知识

  1. 添加 Unity 菜单栏按钮

    通过 Unity 提供的 MenuItem 特性在菜单栏添加选项按钮

    • 特性名:MenuItem
    • 命名空间:UnityEditor

    规则一:一定是静态方法

    规则二:菜单栏按钮必须有至少一个斜杠,不然会报错,不支持只有一个菜单栏入口

    规则三:这个特性可以用在任意的类当中

    [MenuItem("GameTool/Test")]
    private static void Test() {
        AssetDatabase.Refresh();
    }
    
  2. 刷新 Project 窗口内容

    • 类名:AssetDatabase
    • 命名空间:UnityEditor
    • 方法:Refresh
    AssetDatabase.Refresh();
    
  3. Editor 文件夹

    • Editor 文件夹可以放在项目的任何文件夹下,可以有多个
    • 放在其中的内容,项目打包时不会被打包到项目中
    • 一般编辑器相关代码都可以放在该文件夹中

(二)配置工具

  • ExcelTool.cs

    用于将 Excel 配置表内容生成对应的数据结构类容器类2 进制存储文件

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

public class ExcelTool
{
    /// <summary>
    /// Excel 存放的路径
    /// </summary>
    private static readonly string EXCEL_PATH = BinaryDataMgr.EXCEL_PATH;

    /// <summary>
    /// 数据结构类脚本存储位置
    /// </summary>
    private static readonly string DATA_CLASS_PATH = BinaryDataMgr.DATA_CLASS_PATH;

    /// <summary>
    /// 数据容器类脚本存储位置
    /// </summary>
    private static readonly string DATA_CONTAINER_PATH = BinaryDataMgr.DATA_CONTAINER_PATH;

    /// <summary>
    /// 2进制数据存储位置
    /// </summary>
    private static readonly string DATA_BINARY_PATH = BinaryDataMgr.DATA_BINARY_PATH;

    /// <summary>
    /// 2进制文件后缀名
    /// </summary>
    private static readonly string BINARY_SUFFIX = BinaryDataMgr.BINARY_SUFFIX;

    /// <summary>
    /// 变量名所在行
    /// </summary>
    private static readonly int VARIABLE_NAME_ROW = BinaryDataMgr.VARIABLE_NAME_ROW;

    /// <summary>
    /// 变量类型所在行
    /// </summary>
    private static readonly int VARIABLE_TYPE_ROW = BinaryDataMgr.VARIABLE_TYPE_ROW;

    /// <summary>
    /// 变量主键所在行
    /// </summary>
    private static readonly int VARIABLE_KEY_ROW = BinaryDataMgr.VARIABLE_KEY_ROW;

    /// <summary>
    /// 变量主键标识符
    /// </summary>
    private static readonly string[] VARIABLE_KEYS = BinaryDataMgr.VARIABLE_KEYS;

    /// <summary>
    /// 数据内容开始的行号
    /// </summary>
    private static readonly int DATA_BEGIN_ROW_INDEX = BinaryDataMgr.DATA_BEGIN_ROW_INDEX;


    /// <summary>
    /// 生成 Excel 数据信息
    /// </summary>
    [MenuItem("GameTool/GenerateExcel")]
    private static void GenerateExcelInfo() {
        DirectoryInfo dInfo = Directory.CreateDirectory(EXCEL_PATH); // 指定路径的文件夹信息
        FileInfo[]    files = dInfo.GetFiles();                      // 指定路径下的所有 Excel 文件信息
        for (int i = 0; i < files.Length; i++) {
            // 不是 Excel 文件则跳过
            if (files[i].Extension != ".xlsx" && files[i].Extension != ".xls") continue;

            // 获取所有表的数据
            DataTableCollection tableCollection; // 数据表容器
            using (FileStream fs = new FileStream(files[i].FullName, FileMode.Open, FileAccess.Read)) {
                IExcelDataReader excelDataReader = ExcelReaderFactory.CreateOpenXmlReader(fs);
                tableCollection = excelDataReader.AsDataSet().Tables;
            }

            // 遍历所有表的信息,生成相应内容
            foreach (DataTable table in tableCollection) {
                GenerateExcelDataClass(table);  // 生成数据结构类
                GenerateExcelContainer(table);  // 生成容器类
                GenerateExcelBinaryData(table); // 生成2进制数据
            }
        }
    }

    /// <summary>
    /// 生成 Excel 表对应的数据结构类
    /// </summary>
    /// <param name="table">数据表</param>
    private static void GenerateExcelDataClass(DataTable table) {
        DataRow nameRow = table.Rows[VARIABLE_NAME_ROW]; // 变量名行
        DataRow typeRow = table.Rows[VARIABLE_TYPE_ROW]; // 变量类型行

        // 确保数据结构类脚本路径存在
        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 {typeRow[i]} {nameRow[i]};\n";
        }
        str += "}\n";

        // 覆盖写入文件并刷新 Project 窗口
        File.WriteAllText($"{DATA_CLASS_PATH}{table.TableName}.cs", str);
        AssetDatabase.Refresh();
    }

    /// <summary>
    /// 生成 Excel 表对应的数据容器类
    /// </summary>
    /// <param name="table">数据表</param>
    private static void GenerateExcelContainer(DataTable table) {
        int     keyIndex = GetKeyColumnIndex(table);
        DataRow typeRow  = table.Rows[VARIABLE_TYPE_ROW]; // 变量类型行

        // 确保数据容器类脚本路径存在
        if (!Directory.Exists(DATA_CONTAINER_PATH)) {
            Directory.CreateDirectory(DATA_CONTAINER_PATH);
        }

        // 拼接数据结构类内容
        string str = $"using System.Collections.Generic;\n\n" +
                     $"public class {table.TableName}Container\n" +
                     $"{{\n" +
                     $"    public Dictionary<{typeRow[keyIndex]}, {table.TableName}> dataDic = new Dictionary<{typeRow[keyIndex]}, {table.TableName}>();\n" +
                     $"}}\n";

        // 覆盖写入文件并刷新 Project 窗口
        File.WriteAllText($"{DATA_CONTAINER_PATH}{table.TableName}Container.cs", str);
        AssetDatabase.Refresh();
    }

    /// <summary>
    /// 获得主键所在的列
    /// </summary>
    /// <param name="table"></param>
    /// <returns></returns>
    private static int GetKeyColumnIndex(DataTable table) {
        DataRow row = table.Rows[VARIABLE_KEY_ROW]; // 获取变量主键行
        for (int i = 0; i < table.Columns.Count; i++) {
            // 如果该列内容在主键标识符内,则返回该列
            if (VARIABLE_KEYS.Contains(row[i].ToString())) {
                return i;
            }
        }

        return 0; // 否则,返回第一列
    }

    /// <summary>
    /// 生成 Excel 表对应的2进制数据
    /// </summary>
    /// <param name="table">数据表</param>
    private static void GenerateExcelBinaryData(DataTable table) {
        // 确保2进制数据路径存在
        if (!Directory.Exists(DATA_BINARY_PATH)) {
            Directory.CreateDirectory(DATA_BINARY_PATH);
        }

        // 创建 2 进制文件
        using (FileStream fs = new FileStream($"{DATA_BINARY_PATH}{table.TableName}{BINARY_SUFFIX}", FileMode.OpenOrCreate, FileAccess.Write)) {
            int rowNum = table.Rows.Count - DATA_BEGIN_ROW_INDEX + 1; // -DATA_BEGIN_ROW_INDEX 的原因是前 DATA_BEGIN_ROW_INDEX 行是配置规则,不是 2 进制内容

            // 1. 先写入存储的行数
            fs.Write(BitConverter.GetBytes(rowNum), 0, 4);

            // 2. 获取主键的变量名
            string keyName  = table.Rows[VARIABLE_NAME_ROW][GetKeyColumnIndex(table)].ToString();
            byte[] keyBytes = Encoding.UTF8.GetBytes(keyName);
            // 先写长度后写内容
            fs.Write(BitConverter.GetBytes(keyBytes.Length), 0, 4);
            fs.Write(keyBytes, 0, keyBytes.Length);

            // 3. 遍历所有数据内容,进行写入
            DataRow typeRow = table.Rows[VARIABLE_TYPE_ROW];
            for (int i = DATA_BEGIN_ROW_INDEX; i < table.Rows.Count; i++) {
                DataRow row = table.Rows[i];
                for (int j = 0; j < table.Columns.Count; j++) {
                    switch (typeRow[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":
                            byte[] strBytes = Encoding.UTF8.GetBytes(row[j].ToString());
                            fs.Write(BitConverter.GetBytes(strBytes.Length), 0, 4); // 先写入字符串长度
                            fs.Write(strBytes, 0, strBytes.Length);                 // 再写入字符串内容
                            break;
                    }
                }
            }
        }
    }
}
  • BinaryDataMgr.cs

    存储对象数据为 2 进制文件并读取。

using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Runtime.Serialization.Formatters.Binary;
using System.Text;
using UnityEngine;

public class BinaryDataMgr
{
    /// <summary>
    /// 数据存储位置
    /// </summary>
    private static readonly string SAVE_PATH = Application.persistentDataPath + "/Data/";

    /// <summary>
    /// Excel 存放的路径
    /// </summary>
    public static readonly string EXCEL_PATH = Application.dataPath + "/ArtRes/Excel/";

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

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

    /// <summary>
    /// 2进制数据存储位置
    /// </summary>
    public static readonly string DATA_BINARY_PATH = Application.streamingAssetsPath + "/Binary/";

    /// <summary>
    /// 2进制文件后缀名
    /// </summary>
    public static readonly string BINARY_SUFFIX = ".hl";

    /// <summary>
    /// 变量名所在行
    /// </summary>
    public static readonly int VARIABLE_NAME_ROW = 0;

    /// <summary>
    /// 变量类型所在行
    /// </summary>
    public static readonly int VARIABLE_TYPE_ROW = 1;

    /// <summary>
    /// 变量主键所在行
    /// </summary>
    public static readonly int VARIABLE_KEY_ROW = 2;

    /// <summary>
    /// 变量主键标识符
    /// </summary>
    public static readonly string[] VARIABLE_KEYS = { "key", "Key", "KEY" };

    /// <summary>
    /// 数据内容开始的行号
    /// </summary>
    public static readonly int DATA_BEGIN_ROW_INDEX = 4;

    /// <summary>
    /// 存储所有 Excel 表的容器
    /// </summary>
    private Dictionary<string, object> tableDic = new Dictionary<string, object>();
    
    public static BinaryDataMgr Instance { get; set; } = new BinaryDataMgr(); // 需要放在所有字段的最后,保证其他字段先被初始化

    private BinaryDataMgr() {
        InitData();
    }

    /// <summary>
    /// 初始化表格数据
    /// </summary>
    private void InitData() {
        // LoadTable<TowerInfoContainer, TowerInfo>();
    }

    /// <summary>
    /// 加载 Excel 表的2进制数据到内存中
    /// </summary>
    /// <typeparam name="T">容器类名</typeparam>
    /// <typeparam name="K">数据结构体类名</typeparam>
    public void LoadTable<T, K>() {
        using (FileStream fs = new FileStream($"{DATA_BINARY_PATH}{typeof(K)}{BINARY_SUFFIX}", FileMode.Open, FileAccess.Read)) {
            int offset = 0; // 读取偏移量

            // 读取行数
            byte[] rowCountBytes = StreamRead(fs, ref offset, 4);
            int    rowCount      = BitConverter.ToInt32(rowCountBytes, 0);

            // 读取主键名
            byte[] keyNameLengthBytes = StreamRead(fs, ref offset, 4); // 主键名长度
            int    keyNameLength      = BitConverter.ToInt32(keyNameLengthBytes, 0);
            byte[] keyNameBytes       = StreamRead(fs, ref offset, keyNameLength); // 主键名内容
            string keyName            = Encoding.UTF8.GetString(keyNameBytes, 0, keyNameLength);

            // 创建容器类对象
            Type   containerType = typeof(T);
            object container     = Activator.CreateInstance(containerType); // 实例化容器

            Type        classType = typeof(K);
            FieldInfo[] infos     = classType.GetFields(); // 数据结构类所有字段的信息

            // 实例化表的数据内容
            for (int i = 0; i < rowCount; i++) {
                // 实例化数据结构类 对象
                object dataObj = Activator.CreateInstance(classType);
                foreach (FieldInfo info in infos) {
                    if (info.FieldType == typeof(int)) {
                        byte[] bytes = StreamRead(fs, ref offset, 4);
                        int    value = BitConverter.ToInt32(bytes, 0);
                        info.SetValue(dataObj, value);
                    }
                    else if (info.FieldType == typeof(float)) {
                        byte[] bytes = StreamRead(fs, ref offset, 4);
                        float  value = BitConverter.ToSingle(bytes, 0);
                        info.SetValue(dataObj, value);
                    }
                    else if (info.FieldType == typeof(bool)) {
                        byte[] bytes = StreamRead(fs, ref offset, 1);
                        bool   value = BitConverter.ToBoolean(bytes, 0);
                        info.SetValue(dataObj, value);
                    }
                    else if (info.FieldType == typeof(string)) {
                        byte[] bytes      = StreamRead(fs, ref offset, 4); // 长度
                        int    len        = BitConverter.ToInt32(bytes, 0);
                        byte[] valueBytes = StreamRead(fs, ref offset, len); // 内容
                        string value      = Encoding.UTF8.GetString(valueBytes);
                        info.SetValue(dataObj, value);
                    }
                }

                // 添加对象到容器中
                FieldInfo  dicInfo  = containerType.GetField("dataDic");   // 字典字段信息
                object     dicObj   = dicInfo.GetValue(container);         // 获取字典对象
                FieldInfo  keyInfo  = classType.GetField(keyName);         // 主键字段信息
                object     keyValue = keyInfo.GetValue(dataObj);           // 获取主键对象
                MethodInfo mInfo    = dicObj.GetType().GetMethod("Add");   // Add 方法信息
                mInfo?.Invoke(dicObj, new object[] { keyValue, dataObj }); // 执行 Add 方法
            }

            // 记录表的内容
            tableDic.Add(typeof(T).Name, container);
        }
    }

    /// <summary>
    /// 获取表
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <returns></returns>
    public T GetTable<T>() where T : class {
        string tableName = typeof(T).Name;
        if (tableDic.TryGetValue(tableName, out object value)) {
            return value as T;
        }
        return null;
    }

    /// <summary>
    /// 读取对应长度的字节流,offset 会进行更新
    /// </summary>
    /// <param name="stream"></param>
    /// <param name="offset"></param>
    /// <param name="count"></param>
    /// <returns></returns>
    public byte[] StreamRead(Stream stream, ref int offset, int count) {
        byte[] bytes = new byte[count];
        offset = stream.Read(bytes, 0, count);
        return bytes;
    }

    /// <summary>
    /// 存储二进制数据
    /// </summary>
    /// <param name="obj"></param>
    /// <param name="filename"></param>
    public void Save(object obj, string filename) {
        // 如果文件夹不存在,则创建
        if (!Directory.Exists(SAVE_PATH)) {
            Directory.CreateDirectory(SAVE_PATH);
        }

        using (FileStream fs = new FileStream(SAVE_PATH + filename, FileMode.OpenOrCreate, FileAccess.Write)) {
            BinaryFormatter bf = new BinaryFormatter();
            bf.Serialize(fs, obj);
            fs.Close();
        }
    }

    /// <summary>
    /// 读取二进制数据转换为对象
    /// </summary>
    /// <param name="filename"></param>
    /// <typeparam name="T"></typeparam>
    /// <returns></returns>
    public T Load<T>(string filename) where T : class {
        // 如果文件不存在,则返回泛型对象的默认值
        if (!File.Exists(SAVE_PATH + filename)) {
            return default(T);
        }

        T obj = null;
        using (FileStream fs = new FileStream(SAVE_PATH + filename, FileMode.Open, FileAccess.Read)) {
            BinaryFormatter bf = new BinaryFormatter();
            obj = bf.Deserialize(fs) as T;
            fs.Close();
        }

        return obj;
    }
}

(三)演示步骤

1 ExcelTool

​ 在 “BinaryDataMgr.cs” 中的 EXCEL_PATH 下存放数据表 “PlayerInfo.xlsx”,其内容如下:

image-20230821143922335
图1 PlayerInfo.xlsx内容

​ 点击菜单栏的 GameTool -> GenerateExcel,将在 DATA_CLASS_PATHDATA_CONTAINER_PATH 路径下分别生成数据信息脚本和容器脚本:

image-20230821144300610
图2 生成数据信息和容器脚本

2 BinaryMgr

​ 参考如下代码:

  1. 存储数据
Test t = new Test();
t.i = 985;
t.str = "欢迎你";

print(Application.persistentDataPath);
BinaryDataMgr.Instance.Save(t, "哈哈哈");
  1. 获取数据
Test t = BinaryDataMgr.Instance.Load<Test>("哈哈哈");

​ 存储位置可修改 “BinaryDataMgr.cs” 中的 DATA_BINARY_PATH 路径。

​ 具体使用参考代码注释。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

2023-05-29 Unity 2进制5——Excel配置表工具 的相关文章

  • 如何在Excel中创建关系矩阵

    给定一个三元组列表 我想得到一个关系矩阵 如下所示 1 A X 1 A Y 1 B X A B C 1 B Z 1 X Y X Z 2 A Z gt 2 Z X Y 2 B X 3 Y Z 3 A Y 3 A Z 2 C Y 如何 可以在
  • 如何锁定特定单元格但允许过滤和排序

    我使用以下代码来锁定某些单元格的内容 Sub LockCell ws As Worksheet strCellRng As String With ws Unprotect Cells Locked False Range strCellR
  • 将 CSV 导入 Excel - 自动“文本到列”和“插入表格”

    我想在 Excel 2010 上打开 CSV 逗号分隔 文件并自动将文本转换为列 然后选择所有活动单元格并插入带标题的表格 是否可以在我的功能区中添加一个按钮来为我完成这一切 我经常使用不同大小的 CSV 文件 我发现每次手动执行此操作有点
  • 自动计算Excel VBA UDF与单元格属性相关

    我编写了一个 UDF 来计算特定颜色和特定线条样式的单元格 我发布了整个函数 Function CountTime rData As Range cellRefColor As Range As Variant Dim indRefColo
  • 在适用于 Windows 和 Mac 的 VBA 中指定用户文件夹的路径

    我正在编写一个使用 VBA 从 Excel 生成文件的工具 生成的文件将写入用户的 Documents 文件夹中的文件夹 如果存在 e g C Users
  • 尝试使用 Excel 中的 VBA 从网页中提取一个值

    我几天来一直在尝试查找信息 但是我找到的所有示例都只有一小段代码 我需要全部 我想要做的是从主页中提取一个值并将其放入 Excel 的单元格中 然后从同一站点上的另一个页面获取另一个值并放入下一个单元格等 该页面是瑞典证券交易所页面 我用作
  • 根据关键列合并多个 Excel 工作簿

    我从不同的客户那里收到七个工作簿 xlsx 文件 每个工作簿都有一张工作表 每张工作表至少有一个公共 ID 列 UNIQ PK 其中一本工作簿包含所有可能的 id 列表 其他人可能没有所有 id 的记录 但每一行都定义了 id 值 我需要制
  • openpyxl 2.4.2:保存后公式生成的单元格值为空

    我使用 openpyxl 打开文件 编辑一些单元格并保存更改 这是一个例子 import openpyxl book openpyxl load workbook sheet path sheet book active for row i
  • Excel VBA 多张表求和

    我正在尝试创建一个或多个函数 可以将每个客户的考勤卡每日工作时间相加 得出每天的总工作时间 每个客户在一个工作簿中都有自己的工作表 目前 我有一个函数可以确定与第一个客户一起使用的工作表 工作簿中的第三个工作表 Function First
  • Excel工作表中的动态减法公式

    我需要在Excel中编写一个动态减法公式 该公式从其上方的单元格中减去 指定列的 单元格 例如 A2 A1 G1 G列固定 and A3 A2 G2 and A4 A3 G3 等等 Excel 足够智能 可以使用动态引用和对当前单元格的相对
  • 从单元格复制时省略引号

    Problem 当从程序外部的 Excel 复制单元格时 会自动添加双引号 Details 我在 Windows 7 计算机上使用 Excel 2007 如果我有一个具有以下公式的单元格 1 CHAR 9 SOME NOTES FOR LI
  • 如何使用 VBA 忽略范围内的绿色三角形错误,而不逐个单元循环?

    我有一些正在自动化和分发的大型数据集 我想消除警告用户有关存储为文本的数字的绿色小三角形 我使用了以下代码 但在大量纸张上速度非常慢 Range Cells 1 1 Cells lastrow lColumn Select kill tho
  • 如何创建动态变量名VBA

    我正在尝试根据单元格中的值在 VBA 中创建动态数量的变量 本质上我想要的结果是这样的Team1 Team2 to TeamX 任何帮助是极大的赞赏 Dim i x As Integer Set x Range J4 Value Dim T
  • 在 Excel 中打印 MATLAB 图窗并调整其大小

    我在 MATLAB 中有两个带有手柄的图形hFig1 and hFig2 我想将它们打印到 Excel 中的特定单元格 单元格 E3 和 I3 并将它们重新调整为 2 英寸 x 3 英寸 我尝试过使用 AddPictures对象处理程序和使
  • VBScript for Excel:如何选择源数据 (.SetSourceData)?

    我已经在谷歌和这里搜索了这个问题的答案 但没有成功 如果之前有人问过 那么我道歉 我正在尝试使用 VBScript 自动执行一些管理任务 此特定脚本的目的是从文本文件 包含文本和数字列 中获取一些使用情况统计信息 并根据数据制作折线图 创建
  • 在 XSSF 工作簿上设置密码保护

    我想为使用 poi 3 14 创建的 xlsx 文件添加密码保护 该文档声称 这是可能的 http poi apache org cryption html http poi apache org encryption html 使用我尝试
  • 是否有 R 函数可以将这些数据从长形重塑为宽形?

    数据现在看起来如何 Coach ID Student score 1 A 8 1 B 3 2 A 5 2 B 4 2 C 7 看起来像这样 Coach ID Student score student 2 score 2 student 3
  • 强制 Excel 将多张纸作为单个作业打印

    在某些 Excel 2003 工作簿中 当我尝试print如果有多个工作表 Excel 将这些工作表视为单独的打印作业 这让我一直在编写的 Excel 自动化应用程序感到困惑 因为它会导致 Adob e PDF Printer 停止并询问用
  • 如何以可读的方式重写Excel公式?

    我有一个 Excel 文件 其中包含以下公式 IF OR ISERROR G16 ISERROR G17 X16 IF OR G16 xxx G16 yyy G16 zzz Y16 IF G16 333 N A IF G17 333 Z16
  • Pandas - 分割大的Excel文件

    我有一个大约有 500 000 行的 Excel 文件 我想将其拆分为多个 Excel 文件 每个文件有 50 000 行 我想用熊猫来做 这样它会是最快和最简单的 有什么想法如何制作吗 感谢您的帮助 假设您的 Excel 文件只有一个 第

随机推荐

  • 静态分析分析

    软件静态分析概念 静态分析通常是指不执行程序代码而寻找代码中可能存在的错误或评估程序代码的过程 被测对象是各种不软件相关的有必要测试的产物 如文档 源代码等 通过扫描程序正文对程序的数据流和控制流等进行分析 找出系统的缺陷 得出测试报告 不
  • 网络安全实验室CTF练习部分题目(持续更新)

    1 脚本关 微笑一下 过关地址 http lab1 xseclab com base13 ead1b12e47ec7cc5390303831b779d47 index php 查看源代码 include flag php smile 1 i
  • webpack 5 模块联邦实现微前端疑难问题解决

    webpack 5 模块联邦实现微前端疑难问题解决 说明 webpack 5 新增 Module Federation 模块联邦 功能 他可以帮助将多个独立的构建组成一个应用程序 不同的构建可以独立的开发与部署 借助模块联邦我们可以一定程度
  • 什么是思维导图?6 个开源免费的思维导图软件

    目录 15款思维导图工具推荐 什么是思维导图 6 个开源免费的思维导图软件 当前推荐 Freeplane 离线应用 有免安装版本 跨平台 目前 2023年 还在更新中 下载 https sourceforge net projects fr
  • 【CentOS7】-bash: ifconfig: 未找到命令

    安装完CentOS7并配置完网络之后 使用ifconfig命令进行测试出现以下情况 原因分析 缺少ifconfig组件 那么我们可以下载相关的网络组件来解决 yum install y net tools 一波未平 一波又起 出现了一下问题
  • 李飞飞深度学习与计算机视觉——KNN(KNearestNeighbor)

    之前为了熟悉机器学习的东西去搞kaggle的东西 然后就从Titanic入门咯 结果发现并没有对机器学习的东西有深入的理解 做数据挖掘的时候直接调用sklearn里面的框架 根本不用去想机器学习的公式的运用和基础的实现 想用SVM就直接fr
  • Object.defineProperty

    Object defineProperty Object defineProperty obj prop descriptor obj 要在其上定义属性的对象 prop 要定义或修改的属性的名称 descriptor 将被定义或修改的属性描
  • 登录界面测试用例设计

    登录界面测试用例设计 一 界面测试点 1 界面的设计风格是否与UI的设计风格统一 2 界面中的文字简洁易懂 3 界面中没有错别字 二 用户名与密码在输入时 要考虑 1 正确的用户名与正确的密码 2 正确的用户名与错误的密码 3 错误的用户名
  • 腾讯云前端面经

    腾讯云招聘一共四面 第一面是你以后的同事面试 主要考察基础知识 第二面是以后的直属领导 会考察基础原理 以及和职位的匹配度 三面是主管 考察项目等整体 四面为hr面试 一面 一面都比较基础 涉及js vue和网络安全 1 自我介绍 单纯的自
  • 如何使用Go Module代理

    简介 在我们使用Go Module时 golang org x中的文件因为撞墙无法下载 通过改变GOPROXY环境变量可以指定下载源 地址 https mirrors aliyun com goproxy 阿里云的代理仓 https gop
  • QT 帮助文档 使用方法

    我们使用 Qt 帮助文档 主要分为这么几步 1 类使用的相关介绍 2 查看所用部件 类 的相应成员函数 功能 参数 返回值 3 查看部件的信号 4 查看部件的事件 所对应的虚函数如何编写 1 类使用的相关介绍 光标移动到类名字的地方 接着按
  • python 爬虫调用 js 的库之 execjs

    python 爬虫调用 js 的库之 execjs 针对现在大部分的网站都是使用 js 加密 js 加载的 并不能直接抓取出来 这时候就不得不使用一些三方类库来执行 js 语句 1 安装 pip install PyExecJS 2 运行环
  • 你是否看到过如此有趣的AI网站?

    1 营销文案 CopyAI Create Marketing Copy In Seconds 2 美化ppt设计 https www beautiful ai 3 图片修改 https hotpot ai 4 照片变视频 https www
  • shell 多行注释详解

    在我们写 shell 脚本的时候 特别在调试的时候经常需要注释多行命令 但在每一行前输入 显得有些麻烦 基于 shell 命令的灵活性 我们可以使用下面的方法 方法一 这是比较稳妥的作法 可以采用 HERE DOCUMENT 特性 实现多行
  • android应用程序版本管理

    一 版本的主要功能说明 在应用程序的升级 维护策略中 版本是一个关键的组成部分 主要体现在以下几个方面中 1 用户需要了解在他们的设备上所安装的应用程序的版本的特定信息 以及已安装程序的升级版本可用的情况 2 其他应用程序 作为同一个套件中
  • AD20铺铜显示和隐藏的设置

    如果只想隐藏当前选中的铜皮 那么就选中对应需要隐藏的铜 然后鼠标右击 在弹出的对话框中选择 铺铜操作 隐藏选中铺铜 需要隐藏一部分铜皮 即打开铺铜管理器 选择菜单栏中 工具 铺铜 铺铜管理器 在弹出的铺铜管理器对话框中 想将哪些铜皮去进行隐
  • 招行卡中心服务端开发【已offer】

    流程 4 2投递简历 4 9笔试 4 15一面 4 22二面 4 28offer 笔试 卡中心笔试题量偏少 16道选择 两道编程 选择题范围很广 涉及了java c 设计模式 概率统计 信息论与编码 数据库 操作系统 计网等等等等知识点 编
  • C/C++ &与&&

    表示逻辑与的意思 即为and 当运算符两边的表达式的结果都为true时 整个运算结果才为true 否则 只要有一方为false 则结果为false 比如 12 23的结果就是1 12 1 的结果是1 123 0的结果就是0 还具有短路的功能
  • Gdb 调试核心已转存储-调试VINS-FUSION/ORB-SLAM

    GDB调试C 工程非ROS 1 通过运行可执行程序来进入gdb CMakeLists中的修改 SET CMAKE BUILD TYPE Debug SET CMAKE CXX FLAGS DEBUG ENV CXXFLAGS O0 Wall
  • 2023-05-29 Unity 2进制5——Excel配置表工具

    文章目录 一 Excel 读取操作 一 打开 Excel 表 二 获取单元格信息 二 Excel 表配置工具 一 基础知识 二 配置工具 三 演示步骤 1 ExcelTool 2 BinaryMgr 一 Excel 读取操作 一 打开 Ex