【Go】用Go在命令行输出好看的表格
用Go在命令行输出好看的表格
- 前言
- 正文
- 生成Table
- 表头设置
- 插入行
- 表格标题
- 自动标号
- 单元格合并
- 列合并
- 行合并
- 样式设置
- 居中设置
- 数字自动高亮标红
- 完整Demo代码
- 结语
前言
最近在写一些运维小工具,比如批量进行ping包的工具,实现不困难,反正就是ping,统计,然后输出,不过我本着自己既是开发者又是使用者的理念,还是不喜欢输出特别难看的工具,就像这样:
所以就去https://pkg.go.dev/瞄了一眼,看看有没有啥适合的库能够把输出整的好看点的,于是找到了一个库github.com/jedib0t/go-pretty/v6/table
,这是一个在命令行输出格式化表格的库,这里记录一下使用这个库进行一些格式化输出的过程。
其实还有一个比较简单的库叫做gotable,也能实现基础的格式化输出功能,使用起来也方便些,不过功能相对来说就要单一一些,在表格样式设置上会差一些,没那么自由,也可以看下https://pkg.go.dev/github.com/liushuochen/gotable#section-readme
正文
接下来开始正式的去在命令行生成好看的满足需要的表格。
生成Table
首先我们要生成一个Table结构体的实例,可以直接New一个,也可以自己构造:
t := table.Table{}
// 或者
t := table.NewWriter()
NewWriter会返回一个Writer接口
表头设置
表格首先要设置表头,以我的应用为例,表头设置:
header := table.Row{"ID", "IP", "Num", "PacketsRecv", "PacketLoss", "AvgRtt"}
这样生成了一个表头行,然后要通过AppendHeader方法在表格中生效:
t.AppendHeader(header)
看看效果,表头已经打印出来了
+----+----+-----+-------------+------------+--------+
| ID | IP | NUM | PACKETSRECV | PACKETLOSS | AVGRTT |
+----+----+-----+-------------+------------+--------+
+----+----+-----+-------------+------------+--------+
插入行
数据的插入和表头的生成类似,要生成一个table.Row,然后调用AppendRow方法:
func (d *Demo) AppendRow() {for i := 1; i <= 5; i++ {row := table.Row{i, fmt.Sprintf("10.0.0.%v", i), i + 4, i, i, "AppendRow"}d.T.AppendRow(row)}
}
效果如下:
+----+----------+-----+-------------+------------+-----------+
| ID | IP | NUM | PACKETSRECV | PACKETLOSS | AVGRTT |
+----+----------+-----+-------------+------------+-----------+
| 1 | 10.0.0.1 | 5 | 1 | 1 | AppendRow |
| 2 | 10.0.0.2 | 6 | 2 | 2 | AppendRow |
| 3 | 10.0.0.3 | 7 | 3 | 3 | AppendRow |
| 4 | 10.0.0.4 | 8 | 4 | 4 | AppendRow |
| 5 | 10.0.0.5 | 9 | 5 | 5 | AppendRow |
+----+----------+-----+-------------+------------+-----------+
当然也可以生成table.Row的切片后调用一次AppendRows方法,效果和上面是一样的:
func (d *Demo) AppendRows() {var rows []table.Rowfor i := 1; i <= 5; i++ {rows = append(rows, table.Row{i, fmt.Sprintf("10.0.0.%v", i), i + 4, i, i, "AppendRows"})}d.T.AppendRows(rows)
}
+----+----------+-----+-------------+------------+------------+
| ID | IP | NUM | PACKETSRECV | PACKETLOSS | AVGRTT |
+----+----------+-----+-------------+------------+------------+
| 1 | 10.0.0.1 | 5 | 1 | 1 | AppendRow |
| 2 | 10.0.0.2 | 6 | 2 | 2 | AppendRow |
| 3 | 10.0.0.3 | 7 | 3 | 3 | AppendRow |
| 4 | 10.0.0.4 | 8 | 4 | 4 | AppendRow |
| 5 | 10.0.0.5 | 9 | 5 | 5 | AppendRow |
| 1 | 10.0.0.1 | 5 | 1 | 1 | AppendRows |
| 2 | 10.0.0.2 | 6 | 2 | 2 | AppendRows |
| 3 | 10.0.0.3 | 7 | 3 | 3 | AppendRows |
| 4 | 10.0.0.4 | 8 | 4 | 4 | AppendRows |
| 5 | 10.0.0.5 | 9 | 5 | 5 | AppendRows |
+----+----------+-----+-------------+------------+------------+
表格标题
在设置表格实际内容时,还可以设置一个表格标题,如下:
func (d *Demo) AddTitle() {d.T.SetTitle("This is Easy Table")
}
+-------------------------------------------------------------+
| This is Easy Table |
+----+----------+-----+-------------+------------+------------+
| ID | IP | NUM | PACKETSRECV | PACKETLOSS | AVGRTT |
+----+----------+-----+-------------+------------+------------+
| 1 | 10.0.0.1 | 5 | 1 | 1 | AppendRow |
| 2 | 10.0.0.2 | 6 | 2 | 2 | AppendRow |
| 1 | 10.0.0.1 | 5 | 1 | 1 | AppendRows |
| 2 | 10.0.0.2 | 6 | 2 | 2 | AppendRows |
+----+----------+-----+-------------+------------+------------+
自动标号
在插入行的时候,我额外输入了一个ID列,作为标号,其实table提供了相关的方法和接口,只需要调用SetAutoIndex方法,增加自动的索引列即可:
func (d *Demo) MakeHeader() {header := table.Row{"IP", "Num", "PacketsRecv", "PacketLoss", "AvgRtt"}d.T.AppendHeader(header)d.T.SetAutoIndex(true)
}
+------------------------------------------------------------+
| This is Easy Table |
+---+----------+-----+-------------+------------+------------+
| | IP | NUM | PACKETSRECV | PACKETLOSS | AVGRTT |
+---+----------+-----+-------------+------------+------------+
| 1 | 10.0.0.1 | 5 | 1 | 1 | AppendRow |
| 2 | 10.0.0.2 | 6 | 2 | 2 | AppendRow |
| 3 | 10.0.0.1 | 5 | 1 | 1 | AppendRows |
| 4 | 10.0.0.2 | 6 | 2 | 2 | AppendRows |
+---+----------+-----+-------------+------------+------------+
单元格合并
有的时候,相邻单元格的值一样我们可能会想要进行合并,这样更美观,单元格合并分为列合并和行合并;先定义一下这里的列合并和行合并:
- 列合并:针对单列,如果单列中的多个相邻行数据一样,那么就合并为一个大行;
- 行合并:针对单行,如果单行中的多个相邻列数据一样,那么久合并为一个大列;
这里我们用到的原始表格如下:
+--------------------------------------------------------------+
| This is Easy Table |
+---+----------+-------+-------------+------------+------------+
| | IP | NUM | PACKETSRECV | PACKETLOSS | AVGRTT |
+---+----------+-------+-------------+------------+------------+
| 1 | 10.0.0.1 | 5 | 1 | 1 | AppendRow |
| 2 | 10.0.0.2 | 6 | 2 | 2 | AppendRow |
| 3 | 10.0.0.1 | 5 | 1 | 1 | AppendRows |
| 4 | 10.0.0.2 | 6 | 2 | 2 | AppendRows |
+---+----------+-------+-------------+------------+------------+
| | TOTAL | TOTAL | TOTAL | TOTAL | 4 |
+---+----------+-------+-------------+------------+------------+
列合并
我们先进行最后一列AvgRtt的列合并:
func (d *Demo) ColumnMerge() {d.T.SetColumnConfigs([]table.ColumnConfig{{Name: "AvgRtt",// Number是指定列的序号// Number: 5,AutoMerge: true,Align: text.AlignCenter,},})
}
可以选择通过列的表头或者列的序号来选择具体进行合并的列:
+---+----------+-------+-------------+------------+------------+
| | IP | NUM | PACKETSRECV | PACKETLOSS | AVGRTT |
+---+----------+-------+-------------+------------+------------+
| 1 | 10.0.0.1 | 5 | 1 | 1 | AppendRow |
| 2 | 10.0.0.2 | 6 | 2 | 2 | |
| 3 | 10.0.0.1 | 5 | 1 | 1 | AppendRows |
| 4 | 10.0.0.2 | 6 | 2 | 2 | |
+---+----------+-------+-------------+------------+------------+
| | TOTAL | TOTAL | TOTAL | TOTAL | 4 |
+---+----------+-------+-------------+------------+------------+
这样看表格线条不明显,感觉不到区分,那么可以加上一些设置
d.T.Style().Options.SeparateRows = true
+---+----------+-------+-------------+------------+------------+
| | IP | NUM | PACKETSRECV | PACKETLOSS | AVGRTT |
+---+----------+-------+-------------+------------+------------+
| 1 | 10.0.0.1 | 5 | 1 | 1 | AppendRow |
+---+----------+-------+-------------+------------+ |
| 2 | 10.0.0.2 | 6 | 2 | 2 | |
+---+----------+-------+-------------+------------+------------+
| 3 | 10.0.0.1 | 5 | 1 | 1 | AppendRows |
+---+----------+-------+-------------+------------+ |
| 4 | 10.0.0.2 | 6 | 2 | 2 | |
+---+----------+-------+-------------+------------+------------+
| | TOTAL | TOTAL | TOTAL | TOTAL | 4 |
+---+----------+-------+-------------+------------+------------+
行合并
行合并我们对最后一行的汇总行进行合并,具体做法是在添加汇总行时增加RowConfig参数:
func (d *Demo) AppendFooter() {d.T.AppendFooter(table.Row{"Total", "Total", "Total", "Total", count}, table.RowConfig{AutoMerge: true})
}
+---+----------+-------+-------------+------------+------------+
| | IP | NUM | PACKETSRECV | PACKETLOSS | AVGRTT |
+---+----------+-------+-------------+------------+------------+
| 1 | 10.0.0.1 | 5 | 1 | 1 | AppendRow |
+---+----------+-------+-------------+------------+ |
| 2 | 10.0.0.2 | 6 | 2 | 2 | |
+---+----------+-------+-------------+------------+------------+
| 3 | 10.0.0.1 | 5 | 1 | 1 | AppendRows |
+---+----------+-------+-------------+------------+ |
| 4 | 10.0.0.2 | 6 | 2 | 2 | |
+---+----------+-------+-------------+------------+------------+
| | TOTAL | 4 |
+---+---------------------------------------------+------------+
样式设置
现在整个表格已经生成,但我们还需要进行一些美化,这就要对表格的样式进行设置了;
居中设置
对于居中,无法直接进行全局的设置,必须根据列进行,如下:
func (d *Demo) SetAlignCenter() {column := []string{"IP", "Num", "PacketsRecv", "PacketLoss", "AvgRtt"}c := []table.ColumnConfig{}// 根据表格的列数循环进行设置,统一居中for i := 1; i <= len(column); i++ {name := column[i-1]if name == "AvgRtt" {c = append(c, table.ColumnConfig{Name: "AvgRtt",AutoMerge: true,Align: text.AlignCenter,AlignHeader: text.AlignCenter,AlignFooter: text.AlignCenter,})continue}c = append(c, table.ColumnConfig{Name: column[i],Align: text.AlignCenter,AlignHeader: text.AlignCenter,AlignFooter: text.AlignCenter,})}d.T.SetColumnConfigs(c)
}
居中效果如下,这样既能保留列合并又完成了剧中设置:
+---+----------+-------+-------------+------------+------------+
| | IP | NUM | PACKETSRECV | PACKETLOSS | AVGRTT |
+---+----------+-------+-------------+------------+------------+
| 1 | 10.0.0.1 | 5 | 1 | 1 | AppendRow |
+---+----------+-------+-------------+------------+ |
| 2 | 10.0.0.2 | 6 | 2 | 2 | |
+---+----------+-------+-------------+------------+------------+
| 3 | 10.0.0.1 | 5 | 1 | 1 | AppendRows |
+---+----------+-------+-------------+------------+ |
| 4 | 10.0.0.2 | 6 | 2 | 2 | |
+---+----------+-------+-------------+------------+------------+
| | TOTAL | 4 |
+---+---------------------------------------------+------------+
数字自动高亮标红
在我的应用场景中,ping的ip如果出现了丢包情况,那就要红色高亮,方便使用者马上关注到,这种情况下,可以通过Transformer来设置:
func (d *Demo) SetWarnColor() {// 字体颜色WarnColor := text.Colors{text.BgRed}warnTransformer := text.Transformer(func(val interface{}) string {if val.(float64) > 0 {// 统计丢包服务器总数return WarnColor.Sprintf("%.2f%%", val)}return fmt.Sprintf("%v%%", val)})d.T.SetColumnConfigs([]table.ColumnConfig{{Name: "PacketLoss",AutoMerge: true,Align: text.AlignCenter,AlignHeader: text.AlignCenter,AlignFooter: text.AlignCenter,Transformer: warnTransformer,},})
}
实际效果如下:
完整Demo代码
package mainimport ("fmt""math/rand""github.com/jedib0t/go-pretty/v6/table""github.com/jedib0t/go-pretty/v6/text"
)var count = 0type Demo struct {T table.Writer
}func NewDemo() *Demo {return &Demo{T: table.NewWriter(),}
}func (d *Demo) MakeHeader() {header := table.Row{"IP", "Num", "PacketsRecv", "PacketLoss", "AvgRtt"}d.T.AppendHeader(header)d.T.SetAutoIndex(true)// d.T.SetStyle(table.StyleLight)d.T.Style().Options.SeparateRows = true
}func (d *Demo) AddTitle() {d.T.SetTitle("This is Easy Table")
}func (d *Demo) AppendRow() {// rowConfig := table.RowConfig{AutoMerge: true}for i := 1; i <= 2; i++ {row := table.Row{fmt.Sprintf("10.0.0.%v", i), i + 4, i, rand.Float64() * 100, "AppendRow"}count += 1d.T.AppendRow(row)}d.T.AppendRow(table.Row{fmt.Sprintf("10.0.0.%v", 4), 1 + 4, 1, 0.0, "AppendRow"})
}func (d *Demo) AppendRows() {var rows []table.Rowfor i := 1; i <= 2; i++ {rows = append(rows, table.Row{fmt.Sprintf("10.0.0.%v", i), i + 4, i, rand.Float64() * 100, "AppendRows"})count += 1}d.T.AppendRows(rows)
}func (d *Demo) AppendFooter() {d.T.AppendFooter(table.Row{"Total", "Total", "Total", "Total", count}, table.RowConfig{AutoMerge: true, AutoMergeAlign: text.AlignCenter})
}func (d *Demo) ColumnMerge() {d.T.SetColumnConfigs([]table.ColumnConfig{{Name: "AvgRtt",// Number是指定列的序号// Number: 5,AutoMerge: true,Align: text.AlignCenter,},})
}func (d *Demo) SetAlignCenter() {column := []string{"IP", "Num", "PacketsRecv", "PacketLoss", "AvgRtt"}c := []table.ColumnConfig{}// 根据表格的列数循环进行设置,统一居中for i := 1; i <= len(column); i++ {name := column[i-1]if name == "AvgRtt" {c = append(c, table.ColumnConfig{Name: "AvgRtt",AutoMerge: true,Align: text.AlignCenter,AlignHeader: text.AlignCenter,AlignFooter: text.AlignCenter,})continue}c = append(c, table.ColumnConfig{Name: column[i],Align: text.AlignCenter,AlignHeader: text.AlignCenter,AlignFooter: text.AlignCenter,})}d.T.SetColumnConfigs(c)
}func (d *Demo) SetWarnColor() {// 字体颜色WarnColor := text.Colors{text.BgRed}warnTransformer := text.Transformer(func(val interface{}) string {if val.(float64) > 0 {// 统计丢包服务器总数return WarnColor.Sprintf("%.2f%%", val)}return fmt.Sprintf("%v%%", val)})d.T.SetColumnConfigs([]table.ColumnConfig{{Name: "PacketLoss",AutoMerge: true,Align: text.AlignCenter,AlignHeader: text.AlignCenter,AlignFooter: text.AlignCenter,Transformer: warnTransformer,},})
}func (d *Demo) Print() {fmt.Println(d.T.Render())
}func main() {demo := NewDemo()demo.MakeHeader()// demo.AddTitle()demo.AppendRow()demo.AppendRows()// demo.ColumnMerge()demo.AppendFooter()// demo.SetAlignCenter()demo.SetWarnColor()demo.Print()
}
结语
本文介绍了使用第三方库美化Golang的命令行表格格式化输出,除了table以外,go-pretty
库中还包含了进度条、列表等美化方法,感兴趣可以自己看看官方文档。
相关文章:

【Go】用Go在命令行输出好看的表格
用Go在命令行输出好看的表格前言正文生成Table表头设置插入行表格标题自动标号单元格合并列合并行合并样式设置居中设置数字自动高亮标红完整Demo代码结语前言 最近在写一些运维小工具,比如批量进行ping包的工具,实现不困难,反正就是ping&am…...
怎么处理消息重发的问题?
消息队列在消息传递的过程中,如果出现传递失败的情况,发送方会重试,在重试的过程中,可能会产生重复的消息。 消息重复的情况必然存在 关于传递消息时能够提供的服务质量标准,MQTT协议给出了三种不同的标准࿱…...

JVM 运行时数据区(数据区组成表述,程序计数器,java虚拟机栈,本地方法栈)
JVM 运行时数据区JVM 运行时数据区3.1运行时的数据区组成概述3.1.1程度计数器3.1.2java虚拟机栈3.1.3本地方法栈3.1.4java堆3.1.5方法区3.2程序计数器3.3java虚拟机栈3.4本地方法栈JVM 运行时数据区 堆,方法区(元空间) 主要用来存放数据 是线程共享的. 程序计数器,本地方法栈…...
Oracle ASM磁盘组配置、日常运维、故障处理等操作资料汇总
ASM(自动存储管理)在数据库中是非常重要的组成部分,它可以为磁盘提供统一的存储管理、提高磁盘访问的性能和可用性、简化管理复杂度,从而为数据库的运行提供更好的支持。这里就为大家整理了墨天轮数据社区上一些ASM相关基础知识、…...

java对象的创建与内存分配机制
文章目录对象的创建与内存分配机制对象的创建类加载检查分配内存初始化零值设置对象头指向init方法其他:指针压缩对象内存分配对象在栈上分配对象在Eden区中分配大对象直接分配到老年代长期存活的对象进入老年代对象动态年龄判断老年代空间分配担保机制对象的内存回…...

本地存储localStorage、sessionStorage
目录 一、localStorage 二、sessionStorage 三、本地存储处理复杂数据 一、localStorage 介绍 (1)数据存储在用户浏览器中 (2)设置、读取方便、甚至页面刷新不会丢失数据 (3)容量较大,se…...
JavaSE: 网络编程
1.1 概述java程序员面对统一的网络编程环境B/S 架构 和 C/S架构1.2 网络通信的两个要素通信双方的地址:ip 端口号网络通信协议:TCP/IP协议(事实上的国际规则)、OSI模型(理想化)1.3 Inet Address本地回环地…...

计算机图形学09:二维观察之点的裁剪
作者:非妃是公主 专栏:《计算机图形学》 博客地址:https://blog.csdn.net/myf_666 个性签:顺境不惰,逆境不馁,以心制境,万事可成。——曾国藩 文章目录专栏推荐专栏系列文章序一、二维观察基本…...
2023Java 并发编程面试题
Java 并发编程 1、在 java 中守护线程和本地线程区别? java 中的线程分为两种:守护线程(Daemon)和用户线程(User)。任何线程都可以设置为守护线程和用户线程,通过方法Thread.setDaemon(boolon…...

CAD如何绘制A0/A1/A2/A3/A4图框?
在CAD制图时,设计师一般会使用企业的定制图框模板或者个人的特色图框模板,让设计方案更加标准化、规范化。对于新人设计师而言,完成CAD制图已经非常头疼了,图框的绘制更是手忙脚乱。那么是否有更加高效的方式来完成A0、A1、A2、A3…...
R 安装 “umap-learn“ python 包
首先需要在R中下载并读取reticulate包,该包提供了一系列R-Python的交互式命令由于之前在电脑中通过三个方式安装了Python:直接安装 Python 3.10安装Anaconda,携带3.9安装 Miniconda,又是另外一个版本的Python版本各不相同…...
测试同学如何快速开发测试平台?
转眼已经好几个月没有发表什么文章了,因为疫情原因,大家工作都不怎么顺利,没有什么心情。再者,最近一直在搞移动端精准测试的项目,有太多技术难点需要攻克。从各个网站上都找不到解决方案,只能不断地尝试&a…...
【程序员接口百宝箱】免费常用API接口
一、短信发送 短信的应用可以说是非常的广泛了,短信API也是当下非常热门的API~ 短信验证码:可用于登录、注册、找回密码、支付认证等等应用场景。支持三大运营商,3秒可达,99.99%到达率,支持大容量高并发。…...

使数组和能被P整除[同余定理+同余定理变形]
同余定理同余定理变形前言一、使数组和能被P整除二、同余定理变形总结参考资料前言 同余定理非常经典,采用前缀和 map,当两个余数前缀和为一个值时,则中间一段子数组刚好对P整除。但是能否找到前面是否有一段子数组和可以对P整除呐…...
25k的Java开发常问的Synchronized问题有哪些?
前言:面试高频的Synchronized问题大多集中在应用场景、底层实现原理、锁的升级过程。 文章目录 Synchronized定义应用场景对象加锁实现原理JDK6以前JDK6版本及以后对象从无锁到偏向锁转化的过程(大概讲五分钟)轻量级锁升级的过程(大概讲五分钟)自旋锁策略(大概讲五分钟)…...

ES增量同步方案
1 基于业务代码嵌入式的增量同步方式在Java业务代码要修改业务数据的地方,增加调用写入ES数据的方法优点:1、实现方式简单,可控粒度高;2、不依赖第三方数据同步框架;3、数据库不用做特殊配置和部署;缺点&am…...
计算器--课后程序(Python程序开发案例教程-黑马程序员编著-第6章-课后作业)
实例1:计算器 计算器极大地提高了人们进行数字计算的效率与准确性,无论是超市的收银台,还是集市的小摊位,都能够看到计算器的身影。计算器最基本的功能是四则运算。本实例要求编写程序,实现计算器的四则运算功能。 实…...

YOLOv5中添加SE模块详解——原理+代码
目录一、SENet1. 设计原理2. SE Block2.1 Squeeze:Global Information Embedding2.2 Excitation:Adaptive Recalibration3. SE-Inception and SE-ResNet二、YOLOv5中添加SENet1.修改common.py2.修改yolo.py3.修改yolov5s.yaml参考文章一、SENet 论文地址:Squeeze-a…...

arcgispro3.1(账号登陆)
ArcGIS Pro 3.1 更新中文概览专注于 制图、GIS、Python前言:本次更新给了我两个惊喜,一个是本来 ArcMap 就有的功能,另一个明显是学习的 QGIS,嘿嘿,大家往下看吧。整理翻译了一下官方的 ArcGIS Pro 3.1 新特性更新概览…...

VB6换个思路解决微信下载文件只读的问题(含源码)
日期:2023年3月10日 作者:Commas 签名:(ง •_•)ง 积跬步以致千里,积小流以成江海…… 注释:如果您觉得有所帮助,帮忙点个赞,也可以关注我,我们一起成长;如果有不对的地方…...

AI-调查研究-01-正念冥想有用吗?对健康的影响及科学指南
点一下关注吧!!!非常感谢!!持续更新!!! 🚀 AI篇持续更新中!(长期更新) 目前2025年06月05日更新到: AI炼丹日志-28 - Aud…...

第19节 Node.js Express 框架
Express 是一个为Node.js设计的web开发框架,它基于nodejs平台。 Express 简介 Express是一个简洁而灵活的node.js Web应用框架, 提供了一系列强大特性帮助你创建各种Web应用,和丰富的HTTP工具。 使用Express可以快速地搭建一个完整功能的网站。 Expre…...
golang循环变量捕获问题
在 Go 语言中,当在循环中启动协程(goroutine)时,如果在协程闭包中直接引用循环变量,可能会遇到一个常见的陷阱 - 循环变量捕获问题。让我详细解释一下: 问题背景 看这个代码片段: fo…...

智慧工地云平台源码,基于微服务架构+Java+Spring Cloud +UniApp +MySql
智慧工地管理云平台系统,智慧工地全套源码,java版智慧工地源码,支持PC端、大屏端、移动端。 智慧工地聚焦建筑行业的市场需求,提供“平台网络终端”的整体解决方案,提供劳务管理、视频管理、智能监测、绿色施工、安全管…...

3.3.1_1 检错编码(奇偶校验码)
从这节课开始,我们会探讨数据链路层的差错控制功能,差错控制功能的主要目标是要发现并且解决一个帧内部的位错误,我们需要使用特殊的编码技术去发现帧内部的位错误,当我们发现位错误之后,通常来说有两种解决方案。第一…...
渲染学进阶内容——模型
最近在写模组的时候发现渲染器里面离不开模型的定义,在渲染的第二篇文章中简单的讲解了一下关于模型部分的内容,其实不管是方块还是方块实体,都离不开模型的内容 🧱 一、CubeListBuilder 功能解析 CubeListBuilder 是 Minecraft Java 版模型系统的核心构建器,用于动态创…...
oracle与MySQL数据库之间数据同步的技术要点
Oracle与MySQL数据库之间的数据同步是一个涉及多个技术要点的复杂任务。由于Oracle和MySQL的架构差异,它们的数据同步要求既要保持数据的准确性和一致性,又要处理好性能问题。以下是一些主要的技术要点: 数据结构差异 数据类型差异ÿ…...

P3 QT项目----记事本(3.8)
3.8 记事本项目总结 项目源码 1.main.cpp #include "widget.h" #include <QApplication> int main(int argc, char *argv[]) {QApplication a(argc, argv);Widget w;w.show();return a.exec(); } 2.widget.cpp #include "widget.h" #include &q…...
生成 Git SSH 证书
🔑 1. 生成 SSH 密钥对 在终端(Windows 使用 Git Bash,Mac/Linux 使用 Terminal)执行命令: ssh-keygen -t rsa -b 4096 -C "your_emailexample.com" 参数说明: -t rsa&#x…...

【Oracle】分区表
个人主页:Guiat 归属专栏:Oracle 文章目录 1. 分区表基础概述1.1 分区表的概念与优势1.2 分区类型概览1.3 分区表的工作原理 2. 范围分区 (RANGE Partitioning)2.1 基础范围分区2.1.1 按日期范围分区2.1.2 按数值范围分区 2.2 间隔分区 (INTERVAL Partit…...