Unity Debug的简单封装

news2024/9/27 12:16:06

对Unity Debug的简单封装

使用前提:
Project Settings-Player-Other Settings-Script Define Symbols添加 EnableLog,点击Apply
在这里插入图片描述

测试代码:

using MTools.Debuger;
using UnityEngine;

public class NewBehaviourScript : MonoBehaviour
{
    public string TAGNAME = "我是日志的标签";

    void Start()
    {
        Debuger.LogLevel = LogLevel.Error;  //测试,项目中可以通过读取配置文件,更改日志级别

        Debuger.Info("我是一个测试");
        Debuger.Info("NewBehaviourScript", "我是一个测试");
        Debuger.Warn("我是一个测试");
        Debuger.Warn("NewBehaviourScript", "我是一个测试");
        Debuger.Error("我是一个测试");
        Debuger.Error("NewBehaviourScript", "我是一个测试");

        this.Info("我是一个测试2");
        this.Warn("我是一个测试2");
        this.Error("我是一个测试2");
    }
}

效果图:
在这里插入图片描述
日志封装类
Debuger.cs

using System;
using System.IO;
using System.Diagnostics;
using UnityEngine;

namespace MTools.Debuger
{
    /// <summary>
    /// 日志级别
    /// </summary>
    public enum LogLevel : byte
    {
        /// <summary>
        /// 信息级别
        /// </summary>
        Info,

        /// <summary>
        /// 警告级别
        /// </summary>
        Warn,

        /// <summary>
        /// 错误级别
        /// </summary>
        Error
    }

    public class Debuger
    {
        /// <summary>
        /// 日志级别(默认Info)
        /// </summary>
        public static LogLevel LogLevel = LogLevel.Info;
        /// <summary>
        /// 是否使用Unity打印
        /// </summary>
        public static bool UseUnityEngine = true;
        /// <summary>
        /// 是否显示时间
        /// </summary>
        public static bool EnableTime = false;
        /// <summary>
        /// 是否显示堆栈信息
        /// </summary>
        public static bool EnableStack = false;
        /// <summary>
        /// 是否保存到文本
        /// </summary>
        public static bool EnableSave = false;
        /// <summary>
        /// 打印文本流
        /// </summary>
        public static StreamWriter LogFileWriter = null;
        /// <summary>
        /// 日志保存路径(文件夹)
        /// </summary>
        public static string LogFileDir = "";
        /// <summary>
        /// 日志文件名
        /// </summary>
        public static string LogFileName = "";

        //打印格式: {0}-时间 {1}-标签/类名/TAGNAME字段值 {2}-内容
        private static string InfoFormat = "<color=#008000>[Info] {0}<color=#00BFFF>{1}</color> {2}</color>";
        private static string WarnFormat = "<color=#FFFF00>[Warn] {0}<color=#00BFFF>{1}</color> {2}</color>";
        private static string ErrorFormat = "<color=#FF0000>[Error] {0}<color=#00BFFF>{1}</color> {2}</color>";

        private static void Internal_Log(string msg, object context = null)
        {
            bool useUnityEngine = UseUnityEngine;
            if (useUnityEngine)
            {
                UnityEngine.Debug.Log(msg, (UnityEngine.Object)context);
            }
            else
            {
                Console.WriteLine(msg);
            }
        }

        private static void Internal_Warn(string msg, object context = null)
        {
            bool useUnityEngine = UseUnityEngine;
            if (useUnityEngine)
            {
                UnityEngine.Debug.LogWarning(msg, (UnityEngine.Object)context);
            }
            else
            {
                Console.WriteLine(msg);
            }
        }

        private static void Internal_Error(string msg, object context = null)
        {
            bool useUnityEngine = UseUnityEngine;
            if (useUnityEngine)
            {
                UnityEngine.Debug.LogError(msg, (UnityEngine.Object)context);
            }
            else
            {
                Console.WriteLine(msg);
            }
        }

        #region Info
        [Conditional("EnableLog")]
        public static void Info(object message)
        {
            if (LogLevel >= LogLevel.Info)
            {
                string msg = string.Format(InfoFormat, GetLogTime(), "", message);
                Internal_Log(msg, null);
                WriteToFile(msg, false);
            }
        }

        [Conditional("EnableLog")]
        public static void Info(object message, object context)
        {
            if (LogLevel >= LogLevel.Info)
            {
                string msg = string.Format(InfoFormat, GetLogTime(), "", message);
                Internal_Log(msg, context);
                WriteToFile(msg, false);
            }
        }

        [Conditional("EnableLog")]
        public static void Info(string tag, string message)
        {
            if (LogLevel >= LogLevel.Info)
            {
                string msg = string.Format(InfoFormat, GetLogTime(), tag, message);
                Internal_Log(msg, null);
                WriteToFile(msg, false);
            }
        }

        [Conditional("EnableLog")]
        public static void Info(string tag, string format, params object[] args)
        {
            if (LogLevel >= LogLevel.Info)
            {
                string msg = string.Format(format, args);
                msg = string.Format(InfoFormat, GetLogTime(), tag, msg);
                Internal_Log(msg, null);
                WriteToFile(msg, false);
            }
        }
        #endregion

        #region Warn
        [Conditional("EnableLog")]
        public static void Warn(object message)
        {
            if (LogLevel >= LogLevel.Warn)
            {
                string msg = string.Format(WarnFormat, GetLogTime(), "", message);
                Internal_Warn(msg, null);
                WriteToFile(msg, false);
            }
        }

        [Conditional("EnableLog")]
        public static void Warn(object message, object context)
        {
            if (LogLevel >= LogLevel.Warn)
            {
                string msg = string.Format(WarnFormat, GetLogTime(), "", message);
                Internal_Warn(msg, context);
                WriteToFile(msg, false);
            }
        }

        [Conditional("EnableLog")]
        public static void Warn(string tag, string message)
        {
            if (LogLevel >= LogLevel.Warn)
            {
                string msg = string.Format(WarnFormat, GetLogTime(), tag, message);
                Internal_Warn(msg, null);
                WriteToFile(msg, false);
            }
        }

        [Conditional("EnableLog")]
        public static void Warn(string tag, string format, params object[] args)
        {
            if (LogLevel >= LogLevel.Warn)
            {
                string msg = string.Format(format, args);
                msg = string.Format(WarnFormat, GetLogTime(), tag, msg);
                Internal_Warn(msg, null);
                WriteToFile(msg, false);
            }
        }
        #endregion

        #region Error
        [Conditional("EnableLog")]
        public static void Error(object message)
        {
            if (LogLevel >= LogLevel.Error)
            {
                string msg = string.Format(ErrorFormat, GetLogTime(), "", message);
                Internal_Error(msg, null);
                WriteToFile(msg, true);
            }
        }

        [Conditional("EnableLog")]
        public static void Error(object message, object context)
        {
            if (LogLevel >= LogLevel.Error)
            {
                string msg = string.Format(ErrorFormat, GetLogTime(), "", message);
                Internal_Error(msg, context);
                WriteToFile(msg, true);
            }
        }

        [Conditional("EnableLog")]
        public static void Error(string tag, string message)
        {
            if (LogLevel >= LogLevel.Error)
            {
                string msg = string.Format(ErrorFormat, GetLogTime(), tag, message);
                Internal_Error(msg, null);
                WriteToFile(msg, true);
            }
        }

        [Conditional("EnableLog")]
        public static void Error(string tag, string format, params object[] args)
        {
            if (LogLevel >= LogLevel.Error)
            {
                string msg = string.Format(format, args);
                msg = string.Format(ErrorFormat, GetLogTime(), tag, msg);
                Internal_Error(msg, null);
                WriteToFile(msg, true);
            }
        }
        #endregion

        /// <summary>
        /// 获取时间
        /// </summary>
        /// <returns></returns>
        private static string GetLogTime()
        {
            string result = "";
            if (EnableTime)
            {
                result = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff") + " ";
            }
            return result;
        }

        /// <summary>
        /// 序列化打印信息
        /// </summary>
        /// <param name="message">打印信息</param>
        /// <param name="EnableStack">是否开启堆栈打印</param>
        private static void WriteToFile(string message, bool EnableStack = false)
        {
            bool flag = !EnableSave;
            if (!flag)
            {
                bool flag2 = LogFileWriter == null;
                if (flag2)
                {
                    LogFileName = DateTime.Now.GetDateTimeFormats('s')[0].ToString();
                    LogFileName = LogFileName.Replace("-", "_");
                    LogFileName = LogFileName.Replace(":", "_");
                    LogFileName = LogFileName.Replace(" ", "");
                    LogFileName += ".log";
                    bool flag3 = string.IsNullOrEmpty(LogFileDir);
                    if (flag3)
                    {
                        try
                        {
                            bool useUnityEngine = UseUnityEngine;
                            if (useUnityEngine)
                            {
                                LogFileDir = Application.persistentDataPath + "/DebugerLog/";
                            }
                            else
                            {
                                string baseDirectory = AppDomain.CurrentDomain.BaseDirectory;
                                LogFileDir = baseDirectory + "/DebugerLog/";
                            }
                        }
                        catch (Exception ex)
                        {
                            string msg = string.Format(ErrorFormat, "", "", "获取 Application.persistentDataPath 报错!" + ex.Message);
                            Internal_Error(msg, null);
                            return;
                        }
                    }
                    string path = LogFileDir + LogFileName;
                    try
                    {
                        bool flag4 = !Directory.Exists(LogFileDir);
                        if (flag4)
                        {
                            Directory.CreateDirectory(LogFileDir);
                        }
                        LogFileWriter = File.AppendText(path);
                        LogFileWriter.AutoFlush = true;
                    }
                    catch (Exception ex2)
                    {
                        LogFileWriter = null;
                        string msg = string.Format(ErrorFormat, "", "", "LogToCache()" + ex2.Message + ex2.StackTrace);
                        Internal_Error(msg, null);
                        return;
                    }
                }
                bool flag5 = LogFileWriter != null;
                if (flag5)
                {
                    try
                    {
                        LogFileWriter.WriteLine(message);
                        bool flag6 = (EnableStack || Debuger.EnableStack) && UseUnityEngine;
                        if (flag6)
                        {
                            LogFileWriter.WriteLine(StackTraceUtility.ExtractStackTrace());
                        }
                    }
                    catch (Exception)
                    {
                    }
                }
            }
        }
    }
}

日志扩展类
DebugerExtension.cs

using System.Reflection;
using System.Diagnostics;

namespace MTools.Debuger
{
    /// <summary>
    /// 自定义Debuger类的扩展类
    /// </summary>
    public static class DebugerExtension
    {
        [Conditional("EnableLog")]
        public static void Info(this object obj, string message)
        {
            if (Debuger.LogLevel >= LogLevel.Info)
            {
                Debuger.Info(GetLogTag(obj), message);
            }
        }

        [Conditional("EnableLog")]
        public static void Info(this object obj, string format, params object[] args)
        {
            if (Debuger.LogLevel >= LogLevel.Info)
            {
                string message = string.Format(format, args);
                Debuger.Info(GetLogTag(obj), message);
            }
        }

        [Conditional("EnableLog")]
        public static void Warning(this object obj, string message)
        {
            if (Debuger.LogLevel >= LogLevel.Warn)
            {
                Debuger.Warn(GetLogTag(obj), message);
            }
        }

        [Conditional("EnableLog")]
        public static void Warn(this object obj, string format, params object[] args)
        {
            if (Debuger.LogLevel >= LogLevel.Warn)
            {
                string message = string.Format(format, args);
                Debuger.Warn(GetLogTag(obj), message);
            }
        }

        [Conditional("EnableLog")]
        public static void Error(this object obj, string message)
        {
            if (Debuger.LogLevel >= LogLevel.Error)
            {
                Debuger.Error(GetLogTag(obj), message);
            }
        }

        [Conditional("EnableLog")]
        public static void Error(this object obj, string format, params object[] args)
        {
            if (Debuger.LogLevel >= LogLevel.Error)
            {
                string message = string.Format(format, args);
                Debuger.Error(GetLogTag(obj), message);
            }
        }
        /// <summary>
        /// 获取调用打印的类名称或者标记有TAGNAME的字段
        /// 有TAGNAME字段的,触发类名称用TAGNAME字段对应的赋值
        /// 没有用类的名称代替
        /// </summary>
        /// <param name="obj">触发Log对应的类</param>
        /// <returns></returns>
        private static string GetLogTag(object obj)
        {
            FieldInfo field = obj.GetType().GetField("TAGNAME");
            bool flag = field != null;
            string result;
            if (flag)
            {
                result = (string)field.GetValue(obj);
            }
            else
            {
                result = obj.GetType().Name;
            }
            return result;
        }
    }
}

日志拦截器, 实现Unity中Console窗口双击跳转到合理的位置
LogIntercepter.cs

using System;
using System.Reflection;
using UnityEditor;
using UnityEditor.Callbacks;
using UnityEngine;

namespace M.Editor
{
    /// <summary>
    /// 日志拦截器
    /// </summary>
    internal sealed class LogIntercepter
    {
        private static LogIntercepter _current;
        private static LogIntercepter Current
        {
            get
            {
                if (_current == null)
                {
                    _current = new LogIntercepter();
                }
                return _current;
            }
        }

        private Type _consoleWindowType;
        private FieldInfo _activeTextInfo;
        private FieldInfo _consoleWindowInfo;
        private MethodInfo _setActiveEntry;
        private object[] _setActiveEntryArgs;
        private object _consoleWindow;

        private LogIntercepter()
        {
            _consoleWindowType = Type.GetType("UnityEditor.ConsoleWindow,UnityEditor");
            _activeTextInfo = _consoleWindowType.GetField("m_ActiveText", BindingFlags.Instance | BindingFlags.NonPublic);
            _consoleWindowInfo = _consoleWindowType.GetField("ms_ConsoleWindow", BindingFlags.Static | BindingFlags.NonPublic);
            _setActiveEntry = _consoleWindowType.GetMethod("SetActiveEntry", BindingFlags.Instance | BindingFlags.NonPublic);
            _setActiveEntryArgs = new object[] { null };
        }

        [OnOpenAsset]
        private static bool OnOpenAsset(int instanceID, int line)
        {
            UnityEngine.Object instance = EditorUtility.InstanceIDToObject(instanceID);
            if (AssetDatabase.GetAssetOrScenePath(instance).EndsWith(".cs"))
            {
                return Current.OpenAsset();//双击会触发这里
            }
            return false;
        }

        private bool OpenAsset()
        {
            string stackTrace = GetStackTrace();
            if (stackTrace != "")
            {
                //结合条件  可以用来过滤是否使用了原始接口还是自定义的
                if (stackTrace.Contains("[Info]") || stackTrace.Contains("[Warn]") || stackTrace.Contains("[Error]"))
                {
                    string[] paths = stackTrace.Split('\n');

                    for (int i = 0; i < paths.Length; i++)
                    {
                        //过滤日志封装类和日志扩展类
                        if (!paths[i].Contains("Debuger.cs") && !paths[i].Contains("DebugerExtension.cs") && paths[i].Contains(" (at "))
                        {
                            return OpenScriptAsset(paths[i]);
                        }
                    }
                }
            }
            return false;
        }

        private bool OpenScriptAsset(string path)
        {
            int startIndex = path.IndexOf(" (at ") + 5;
            int endIndex = path.IndexOf(".cs:") + 3;
            string filePath = path.Substring(startIndex, endIndex - startIndex);
            string lineStr = path.Substring(endIndex + 1, path.Length - endIndex - 2);
            TextAsset asset = AssetDatabase.LoadAssetAtPath<TextAsset>(filePath);
            if (asset != null)
            {
                int line;
                if (int.TryParse(lineStr, out line))
                {
                    object consoleWindow = GetConsoleWindow();
                    _setActiveEntry.Invoke(consoleWindow, _setActiveEntryArgs);

                    EditorGUIUtility.PingObject(asset);
                    AssetDatabase.OpenAsset(asset, line);
                    return true;
                }
            }
            return false;
        }

        private string GetStackTrace()
        {
            object consoleWindow = GetConsoleWindow();

            if (consoleWindow != null)
            {
                if (consoleWindow == EditorWindow.focusedWindow as object)
                {
                    object value = _activeTextInfo.GetValue(consoleWindow);
                    return value != null ? value.ToString() : "";
                }
            }
            return "";
        }

        private object GetConsoleWindow()
        {
            if (_consoleWindow == null)
            {
                _consoleWindow = _consoleWindowInfo.GetValue(null);
            }
            return _consoleWindow;
        }
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/56211.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

基于PHP+MySQL家庭医生签约预约诊疗管理信息系统

随着时代的发展,人们对医疗方面的要求也越来越高,也是人们更希望通过家庭医生来对自己提供所需的医疗服务,从而享受更加个性化的医疗服务,为此我们开发了本家庭医生签约预约诊疗管理信息系统,通过本系统患者可以享有签约,预约,和诊疗等一系类的服务。 本系统是一个家庭医生签约…

[附源码]Python计算机毕业设计Django基于微信小程序的网络办公系统

项目运行 环境配置&#xff1a; Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术&#xff1a; django python Vue 等等组成&#xff0c;B/S模式 pychram管理等等。 环境需要 1.运行环境&#xff1a;最好是python3.7.7&#xff0c;…

qmake 参数

E:\workspace\QtWork\qmake\option.cpp:Option::init() -project 设置qmake生成工程相关文件&#xff0c;如果用qt creator开发的话这个命令参数基本用不到。 -prl 设置qmake生成prl文件。 -set 设置自定义属性&#xff0c;会存放到注册表中。具体参考属性 -unset 取消自定义…

网页JS自动化脚本(六)在特定位置添加元素

在某元素后插入元素 我们这一次在按钮元素后面复制一个一模一样的按钮,所以分为几个步骤,先新建一个一样的元素,然后把相同中的属性赋值给它,再插入到合适的位置,最后再稍微修改一下外观样式即可 首先新建一个input元素,看一下效果 window.onloadfunction(){var theElementdo…

[附源码]Python计算机毕业设计Django基于人脸识别的社区防疫管理系统

项目运行 环境配置&#xff1a; Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术&#xff1a; django python Vue 等等组成&#xff0c;B/S模式 pychram管理等等。 环境需要 1.运行环境&#xff1a;最好是python3.7.7&#xff0c;…

Pytest自动化测试框架---(单元测试框架)

unittest是python自带的单元测试框架&#xff0c;它封装好了一些校验返回的结果方法和一些用例执行前的初始化操作&#xff0c;使得单元测试易于开展&#xff0c;因为它的易用性&#xff0c;很多同学也拿它来做功能测试和接口测试&#xff0c;只需简单开发一些功能&#xff08;…

阿里云新用户活动:云服务器ECS 新购、升级报价出炉了!

阿里云新人特惠&#xff0c;阿里云新用户新购升级立享满减&#xff0c;新购升级云服务器ECS &#xff0c;购买热门产品 s6/u1/c6/g6/r6/c7/g7/r7指定配置&#xff0c;可享折上折&#xff01;从未购买过云服务器ECS或者轻量应用服务器的用户一次性可领取3张优惠券。优惠券适用于…

深入浅出Seata的AT模式

单个掉队&#xff0c;导致集体被动摆烂&#xff1b; 一、业务背景 在分布式架构中&#xff0c;事务管理是个无法避开的复杂问题&#xff0c;虽然有多种解决方案&#xff0c;但是需要根据业务去选择合适的&#xff1b; 从个人最近几年的实践经验来看&#xff0c;Seata组件的AT…

【JUC】SpringBoot使用线程池的两种方式 注解和注入

学习笔记一、ThreadPoolTaskExecutor与ThreadPoolExecutor的区别二、编写配置文件ThreadPoolConfig二、编写Controller三、编写Service3.1、注解3.1、注入一、ThreadPoolTaskExecutor与ThreadPoolExecutor的区别 ThreadPoolExecutor 是JDK自1.5添加的线程池。 ThreadPoolTaskE…

排序算法:插入排序,选择排序,冒泡排序

插入排序 一般来说&#xff0c;插入排序都采用in-place在数组上实现。具体算法描述如下&#xff1a; 步骤1: 从第一个元素开始&#xff0c;该元素可以认为已经被排序&#xff1b; 步骤2: 取出下一个元素&#xff0c;在已经排序的元素序列中从后向前扫描&#xff1b; 步骤3: 如…

[附源码]计算机毕业设计-中国传统手工艺销售平台Springboot程序

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

[附源码]计算机毕业设计JAVA校园失物招领平台

[附源码]计算机毕业设计JAVA校园失物招领平台 项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybati…

李峋同款会动的爱心Python代码版

最近看到不少关于李峋同款爱心的视频、文章&#xff0c;今天我们也分享一下李峋同款爱心 Python 代码版。要问李峋是谁&#xff1f;我也不太清楚&#xff0c;大家可自行百度&#xff0c;这个是我百度的结果&#xff0c;仅供参考。 简单来说李峋同款爱心就是一个动态的♥型效果&…

【STM32学习(1)】详解STM32时钟体系

一、8051和stm32时钟体系结构区别 HSE&#xff1a;外部高速的振荡时钟&#xff08;8MHZ&#xff09; HSI&#xff1a;内部高速的振荡时钟&#xff08;16MHZ&#xff09; LSI&#xff1a;内部低速的振荡时钟&#xff08;32KHZ&#xff09; LSK&#xff1a;外部低速的振荡时钟&a…

HTML+CSS+JS静态网页设计【篮球NBA介绍体育运动】web前端学生作业源码

&#x1f389;精彩专栏推荐 &#x1f4ad;文末获取联系 ✍️ 作者简介: 一个热爱把逻辑思维转变为代码的技术博主 &#x1f482; 作者主页: 【主页——&#x1f680;获取更多优质源码】 &#x1f393; web前端期末大作业&#xff1a; 【&#x1f4da;毕设项目精品实战案例 (10…

【学习笔记】DDD领域驱动设计篇

【学习笔记】DDD领域驱动设计篇 文章目录【学习笔记】DDD领域驱动设计篇什么是DDD&#xff1f;DDD的优缺点DDD的架构框架详解User Interface层application层domain层infrastructure层结语什么是DDD&#xff1f; DDD 是 Domain driven design &#xff08;领域驱动设计&#xf…

GIS工具maptalks开发手册(四)02——渲染地图信息框之添加绘制工具 获取面的坐标数据信息框进行展示 渲染图片的两种方式

GIS工具maptalks开发手册(四)02——渲染地图信息框之添加绘制工具 & 获取面的坐标数据信息框进行展示 & 渲染图片的两种方式 效果-获取面的坐标 效果-渲染图片的2种方式 代码 index.html <!DOCTYPE html> <html> <meta charset"UTF-8">…

[附源码]计算机毕业设计springboot校园招聘系统设计

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

家装家居行业该如何进行网络推广?

咱们这里谈家居家装行业&#xff0c;指得是置办新家的大件产品&#xff0c;不是锅碗瓢盆&#xff0c;也不是床单被罩那些。如衣柜、橱柜、灯具、智能马桶、窗户、瓷砖、沙发、床等等这些是咱们讨论的范围。 在家装家居行业中&#xff0c;每个产品的客单价通常很高&#xff0c;回…

更改 HIVE 表字段数据类型有哪些注意事项?

更改 HIVE 表字段数据类型有哪些注意事项&#xff1f; 1. 使用 HIVE 表的常见规范 在大数据离线分析场景中&#xff0c;在数据建模/表格式这一层&#xff0c;目前使用最多的还是 APACHE HIVE 这一数据仓库框架&#xff08;湖仓一体的框架&#xff0c;如 Iceberg/DeltaLake/Hu…