【Viper】配置格式与支持的数据源与go案例
Viper 是一个用于 Go 应用程序的配置管理库,支持多种配置格式和数据源。
安装依赖
go get github.com/spf13/viper
go get github.com/spf13/viper/remote
go get go.etcd.io/etcd/client/v3
"github.com/spf13/viper/remote"
要写在etcd客户端import里
1. 配置格式—就是可以读的配置类型
Viper 支持多种常见的配置格式,包括:
- JSON: 一种轻量级的数据交换格式,易于阅读和编写。
- YAML: 一种人类可读的数据序列化格式,常用于配置文件。
- TOML: 一种易于阅读的配置文件格式,旨在成为最小的配置文件格式。
- HCL: HashiCorp 配置语言,用于描述基础设施配置。
- Java Properties: 一种简单的键值对格式,常用于 Java 应用程序。
- INI: 一种简单的配置文件格式,常用于 Windows 应用程序。
- Envfile: 环境变量文件格式,通常用于存储环境变量。
2. 支持的数据源—可以从哪里导入要读的配置
Viper 不仅支持从文件中读取配置,还支持从多种数据源获取配置,包括:
- 文件: 从本地文件系统中读取配置文件。
- 环境变量: 从操作系统的环境变量中读取配置。
- io.Reader: 从Reader中读取配置。
- 远程配置系统: 从远程配置系统(如 etcd、Consul)中读取配置。
Viper 支持的四种常见数据源的简单实现:
1. 文件
Viper 支持从多种文件格式中读取配置,包括 JSON、YAML、TOML、HCL、INI 等。
使用方法
- 设置配置文件路径和名称:
viper.SetConfigName("config") // 配置文件名称(不带扩展名) viper.SetConfigType("yaml") // 配置文件类型(如 yaml、json 等) viper.AddConfigPath(".") // 配置文件搜索路径
- 读取配置文件:
if err := viper.ReadInConfig(); err != nil {log.Fatalf("Error reading config file: %s", err) }
示例
假设有一个 config.yaml
文件:
database:host: localhostport: 5432
读取配置:
viper.SetConfigName("config")
viper.SetConfigType("yaml")
viper.AddConfigPath(".")
if err := viper.ReadInConfig(); err != nil {log.Fatal(err)
}
fmt.Println("Database Host:", viper.GetString("database.host"))
fmt.Println("Database Port:", viper.GetInt("database.port"))
2. 环境变量
Viper 可以从操作系统的环境变量中读取配置,适合在容器化或云原生环境中使用。
使用方法
- 启用环境变量支持:
viper.AutomaticEnv() // 自动绑定环境变量
- 设置环境变量前缀(可选):
viper.SetEnvPrefix("MYAPP") // 环境变量前缀(如 MYAPP_DATABASE_HOST)
- 绑定特定键到环境变量:
viper.BindEnv("database.host", "DB_HOST") // 将 database.host 绑定到环境变量 DB_HOST
示例
假设设置了环境变量:
export DB_HOST=localhost
export DB_PORT=5432
读取配置:
viper.AutomaticEnv()
viper.BindEnv("database.host", "DB_HOST")
viper.BindEnv("database.port", "DB_PORT")
fmt.Println("Database Host:", viper.GetString("database.host"))
fmt.Println("Database Port:", viper.GetInt("database.port"))
3. io.Reader
Viper 支持从实现了 io.Reader
接口的对象中读取配置,适合从内存或网络流中加载配置。
使用方法
- 从
io.Reader
读取配置:configData := []byte(`{"database": {"host": "localhost", "port": 5432}}`) reader := bytes.NewReader(configData) viper.SetConfigType("json") // 设置配置类型 if err := viper.ReadConfig(reader); err != nil {log.Fatal(err) }
示例
configData := []byte(`
database:host: localhostport: 5432
`)
reader := bytes.NewReader(configData)
viper.SetConfigType("yaml")
if err := viper.ReadConfig(reader); err != nil {log.Fatal(err)
}
fmt.Println("Database Host:", viper.GetString("database.host"))
fmt.Println("Database Port:", viper.GetInt("database.port"))
4. etcd
Viper 支持从 etcd(分布式键值存储)中读取配置,适合分布式系统的配置管理。
使用方法
- 安装 etcd 支持:
go get github.com/spf13/viper/remote
- 配置 etcd 客户端:
import ("github.com/spf13/viper"_ "github.com/spf13/viper/remote" )
- 从 etcd 读取配置:
viper.AddRemoteProvider("etcd", "http://127.0.0.1:2379", "/config/path") viper.SetConfigType("yaml") // 设置配置类型 if err := viper.ReadRemoteConfig(); err != nil {log.Fatal(err) }
示例
假设 etcd 中存储了以下配置:
database:host: localhostport: 5432
读取配置:
viper.AddRemoteProvider("etcd", "http://127.0.0.1:2379", "/config/path")
viper.SetConfigType("yaml")
if err := viper.ReadRemoteConfig(); err != nil {log.Fatal(err)
}
fmt.Println("Database Host:", viper.GetString("database.host"))
fmt.Println("Database Port:", viper.GetInt("database.port"))
总结
- 文件:适合本地开发和静态配置。
- 环境变量:适合容器化或云原生环境。
- io.Reader:适合从内存或网络流中加载配置。
- etcd:适合分布式系统的动态配置管理。
综合go案例
config.env
env=dev
server.ip=127.0.0.1
server.port=8080
courses=["golang", "C/C++", "音视频", "kernel", "dpdk", "面试题", "游戏"]
config.json
{"env": "dev","server": {"ip":"127.0.0.1","port": 8085},"courses": ["golang","C/C++","音视频","kernel","dpdk","面试题","游戏"],"list": [{"name": "golang","author": "nick"},{"name": "C/C++","author": "king"},{"name": "kernel","author": "vico"},{"name": "音视频","author": "Darren"},{"name": "游戏","author": "mark"}]
}
config.noext
# 键值
env: dev
# 对象或map
server:ip: 127.0.0.1port: 8080
# 数组或列表
courses:- "golang"- "C/C++"- "音视频"- "kernel"- "dpdk"- "面试题"- "游戏"list:- name: golangauthor: nick- name: C/C++author: king- name: kernelauthor: vico- name: 音视频author: Darren- name: 游戏author: mark
config.yaml
# 键值
env: dev
# 对象或map
server:ip: 127.0.0.1port: 8080
# 数组或列表
courses:- "golang"- "C/C++"- "音视频"- "kernel"- "dpdk"- "面试题"- "游戏"list:- name: golangauthor: nick- name: C/C++author: king- name: kernelauthor: vico- name: 音视频author: Darren- name: 游戏author: mark
data_source.go
package configimport ("github.com/spf13/viper"_ "github.com/spf13/viper/remote""io""log"
)// LoadFromFile 加载配置文件。
// 该函数使用 vipers 去从指定的文件路径加载配置。
// 参数:
//
// filepath - 配置文件的路径。
// typ - 可选参数,指定配置文件的类型。
//
// 返回值:
//
// *viper.Viper - 加载了配置文件数据的 viper 实例。
// error - 如果加载配置文件时发生错误,返回该错误。
func LoadFromFile(filepath string, typ ...string) (*viper.Viper, error) {// 创建一个新的 viper 实例。v := viper.New()// 设置配置文件的路径。v.SetConfigFile(filepath)// 如果提供了配置文件类型,则设置配置文件类型。if len(typ) > 0 {v.SetConfigType(typ[0])}// 读取并解析配置文件到viper中。err := v.ReadInConfig()// 返回 viper 实例和可能的错误。return v, err
}// LoadFromEnv 初始化一个viper实例,并将其配置为自动从环境变量中加载配置。
// 该函数返回一个指向viper实例的指针,以及一个错误(此示例中未实现错误处理)。
func LoadFromEnv() (*viper.Viper, error) {// 创建一个新的viper实例。v := viper.New()// 启用自动环境变量加载,viper将自动查找与结构体字段同名的环境变量。//v.AutomaticEnv()// 手动绑定环境变量GOPATH和GOROOT到viper实例。// 这样做是为了方便地从环境变量中读取这些值,而无需手动查询环境变量。v.BindEnv("GOPATH")v.BindEnv("GOROOT")// 返回viper实例指针,以及nil作为错误值,表示没有发生错误。return v, nil
}// LoadFromIoReader 从 io.Reader 类型的参数中加载配置信息。
// 此函数主要用于从不同的读取源(如文件、网络流等)中加载配置,
// 并根据提供的 typ 参数设置配置的类型。
// 参数:
// - reader: io.Reader 类型的接口,代表任何可以读取字节流的对象。
// - typ: 字符串,指定配置文件的类型(例如 "json"、"yaml")。
//
// 返回值:
// - *viper.Viper: 一个指向 viper.Viper 实例的指针,用于进一步操作或获取配置信息。
// - error: 在读取配置过程中遇到的错误(如果有)。
func LoadFromIoReader(reader io.Reader, typ string) (*viper.Viper, error) {// 创建一个新的 viper 实例。v := viper.New()// 设置配置类型,根据传入的 typ 参数。v.SetConfigType(typ)// 从 reader 参数指定的源中读取配置信息。err := v.ReadConfig(reader)// 返回 viper 实例和可能的错误。return v, err
}// LoadFromEtcd loadFromEtcd 从 Etcd 中加载配置信息。
// 参数:
//
// etcdAddr: Etcd服务器的地址。
// key: 配置在Etcd中的键路径。
// typ: 配置文件的类型。
//
// 返回值:
//
// *viper.Viper: 加载配置后的Viper实例指针。
// error: 错误信息,如果有的话。
func LoadFromEtcd(etcdAddr, key, typ string) (*viper.Viper, error) {// 创建一个新的Viper实例。v := viper.New()// 为Viper实例添加Etcd3远程提供者。// 这里可能会出现错误,如果提供的Etcd地址或键路径无效。err := v.AddRemoteProvider("etcd3", etcdAddr, key)if err != nil {// 记录错误信息。log.Println(err)// 返回nil和错误信息。return nil, err}// 设置Viper实例的配置类型。v.SetConfigType(typ)// 从远程提供者读取配置信息。// 这里可能会出现错误,如果无法从远程提供者获取配置信息。err = v.ReadRemoteConfig()// 返回Viper实例和可能的错误信息。return v, err
}
main.go
package mainimport ("bytes""context""fmt"clientv3 "go.etcd.io/etcd/client/v3""golang20-viper/config""log""os"
)func main() {//loadFile()//loadEnv()//loadReader()loadEtcd()
}// loadFile 函数演示了如何从不同格式的配置文件中加载配置。
// 它依次尝试加载 .env, .json, .yaml, .toml 和 .yaml 文件,并打印出特定配置项的值。
func loadFile() {// 从 "config.env" 文件加载配置,并打印出环境、服务器端口和课程信息。v1, err := config.LoadFromFile("config.env", "env")fmt.Println("config.env", err, v1.Get("env"), v1.Get("server.port"), v1.Get("courses"))// 从 "config.json" 文件加载配置,包括环境、服务器端口、课程信息和作者信息。v2, err := config.LoadFromFile("config.json")fmt.Println("config.json", err, v2.Get("env"), v2.Get("server.port"), v2.Get("courses").([]any)[0], v2.Get("list").([]any)[0].(map[string]any)["author"])// 从 "config.noext" 文件加载 YAML 格式的配置,同样打印环境、服务器端口、课程信息和作者信息。v3, err := config.LoadFromFile("config.noext", "yaml")fmt.Println("config.noext", err, v3.Get("env"), v3.Get("server.port"), v3.Get("courses").([]any)[0], v3.Get("list").([]any)[0].(map[string]any)["author"])// 从 "config.toml" 文件加载配置,展示如何获取嵌套配置项的值。v4, err := config.LoadFromFile("config.toml")fmt.Println("config.toml", err, v4.Get("env"), v4.Get("server.port"), v4.Get("courses").(map[string]any)["list"].([]any)[0], v4.Get("list").([]any)[0].(map[string]any)["author"])// 从 "config.yaml" 文件加载配置,再次打印出环境、服务器端口、课程信息和作者信息,验证不同格式文件的兼容性。v5, err := config.LoadFromFile("config.yaml")fmt.Println("config.yaml", err, v5.Get("env"), v5.Get("server.port"), v5.Get("courses").([]any)[0], v5.Get("list").([]any)[0].(map[string]any)["author"])
}func loadEnv() {v, err := config.LoadFromEnv()fmt.Println(err, v.Get("GOROOT"), v.Get("gopath"))
}// loadReader 读取配置文件并解析特定配置项。
// 该函数没有输入参数和返回值。
// 功能描述:
// 1. 读取名为 "config.yaml" 的配置文件。
// 2. 如果读取过程中遇到错误,记录错误信息并终止程序运行。
// 3. 使用 bytes.NewReader 创建一个字节流读取器来读取配置文件内容。
// 4. 调用 config.LoadFromIoReader 函数从字节流读取器中加载配置信息。
// 5. 打印解析后的配置项,包括环境变量、服务器端口、课程信息和作者信息。
func loadReader() {// 读取配置文件 "config.yaml" 的内容到 byteList。byteList, err := os.ReadFile("config.yaml")if err != nil {// 如果读取配置文件时发生错误,记录错误信息并终止程序。log.Fatalln(err)}// 创建一个新的字节流读取器来读取配置文件内容。r := bytes.NewReader(byteList)// 从字节流读取器中加载配置信息,并处理可能的错误。v, err := config.LoadFromIoReader(r, "yaml")// 打印解析后的配置项。fmt.Println("io.reader", err, v.Get("env"), v.Get("server.port"), v.Get("courses").([]any)[0], v.Get("list").([]any)[0].(map[string]any)["author"])
}// loadEtcd 函数用于从本地文件加载配置并写入到 etcd 中,然后从 etcd 中读取配置并打印部分配置项。
// 该函数不接收任何参数,也不返回任何值。
func loadEtcd() {// 定义 etcd 的地址、配置项的键以及本地配置文件的路径etcdAddr := "192.168.88.131:2379"key := "/0voice/viper/config.yaml"loaclFilepath := "config.yaml"// 将本地配置文件的内容写入到 etcd 中writeConfToEtcd(etcdAddr, key, loaclFilepath)// 从 etcd 中加载配置,并解析为 yaml 格式v, err := config.LoadFromEtcd(etcdAddr, key, "yaml")// 打印从 etcd 中读取的配置项,包括环境、服务器端口、课程列表中的第一个课程以及列表中的第一个作者的名称fmt.Println("etcd", err, v.Get("env"), v.Get("server.port"), v.Get("courses").([]any)[0], v.Get("list").([]any)[0].(map[string]any)["author"])//fmt.Println(err, v)
}// writeConfToEtcd 将本地配置文件内容写入到etcd指定键中
// 参数说明:
// - etcdAddr: etcd服务地址,格式为"IP:PORT"
// - key: etcd中存储配置的键名
// - localFilepath: 本地配置文件的路径
//
// 功能说明:
//
// 读取配置文件,将其内容存入etcd集群的指定键中
// 遇到任何错误(文件读取、连接etcd、写入etcd)将直接终止程序
func writeConfToEtcd(etcdAddr, key, localFilepath string) {// 从固定路径读取配置文件内容byteList, err := os.ReadFile(localFilepath)if err != nil {// 如果读取配置文件时发生错误,记录错误信息并终止程序。log.Fatalln(err)}v := string(byteList)// 创建etcd客户端连接cli, err := clientv3.New(clientv3.Config{Endpoints: []string{etcdAddr},})if err != nil {log.Fatal(err)}// 将配置内容写入etcd指定键_, err = cli.Put(context.Background(), key, v)if err != nil {log.Fatal(err)}
}
etcd docker部署
docker run -d \
-p 2379:2379 \
-p 2380:2380 \
--restart always \
--volume=/home/etcd:/etcd-data \
--name etcd quay.io/coreos/etcd:v3.5.7 \
/usr/local/bin/etcd \
--data-dir=/etcd-data --name node1 \
--initial-advertise-peer-urls http://192.168.239.161:2380 \
--listen-peer-urls http://0.0.0.0:2380 \
--advertise-client-urls http://192.168.239.161:2379 \
--listen-client-urls http://0.0.0.0:2379 \
--initial-cluster node1=http://192.168.239.161:2380 \
--initial-cluster-token tkn \
--initial-cluster-state new
https://github.com/0voice
相关文章:
【Viper】配置格式与支持的数据源与go案例
Viper 是一个用于 Go 应用程序的配置管理库,支持多种配置格式和数据源。 安装依赖 go get github.com/spf13/viper go get github.com/spf13/viper/remote go get go.etcd.io/etcd/client/v3"github.com/spf13/viper/remote"要写在etcd客户端import里 1…...

C++17 中的 std::reduce:详细教程
文章目录 1. 简介2. 函数签名3. 使用场景3.1 简单的累加操作3.2 自定义归并操作3.3 并行计算的性能优势 4. 注意事项4.1 归并操作的结合律和交换律4.2 默认值的使用 5. 总结 1. 简介 std::reduce 是 C17 标准库中引入的一个算法,用于对范围内的元素进行归并操作。它…...

解决 paddle ocr 遇到 CXXABI_1.3.13 not found 的问题
ImportError: /lib/x86_64-linux-gnu/libstdc.so.6: version CXXABI_1.3.13 not found (required by /home/hum/anaconda3/envs/ipc/lib/python3.11/site-packages/paddle/base/libpaddle.so) 通过命令检查 strings /lib/x86_64-linux-gnu/libstdc.so.6|grep CXXABI 而实际上我…...
探索 Text-to-SQL 技术:从自然语言到数据库查询的桥梁
亲爱的小伙伴们😘,在求知的漫漫旅途中,若你对深度学习的奥秘、Java 与 Python 的奇妙世界,亦或是读研论文的撰写攻略有所探寻🧐,那不妨给我一个小小的关注吧🥰。我会精心筹备,在未来…...
mac搭建环境
从0-1搭建mac环境 先查看自己的芯片信息 bash uname -mbash-3.2$ uname -m arm64这里是自己的型号安装brew xcode-select --install xcode-select -p /bin/zsh -c “$(curl -fsSL https://gitee.com/cunkai/HomebrewCN/raw/master/Homebrew.sh)” source /Users/lanren/.…...

算法学习笔记之贪心算法
导引(硕鼠的交易) 硕鼠准备了M磅猫粮与看守仓库的猫交易奶酪。 仓库有N个房间,第i个房间有 J[i] 磅奶酪并需要 F[i] 磅猫粮交换,硕鼠可以按比例来交换,不必交换所有的奶酪 计算硕鼠最多能得到多少磅奶酪。 输入M和…...
Docker 镜像标签使用
写在前面 当使用命令 docker pull mysql 拉取镜像时,其实等价于如下命令 docker pull mysql:latest latest 是默认的标签,字面上理解为最新版本的镜像,实质上 latest 只是镜像的标签名称,跟具体某个版本号地位一样,…...

STM32之SG90舵机控制
目录 前言: 一、硬件准备与接线 1.1 硬件清单 1.2 接线 二、 SG90舵机简介 1.1 外观 1.2 基本参数 1.3 引脚说明 1.4 控制原理 1.5 特点 1.6 常见问题 三、 单片机简介 四、 程序设计 4.1 定时器配置 4.2 角度控制函数 4.3 主函数调用 五、 总结 …...

VSCode Error Lens插件介绍(代码静态检查与提示工具)(vscode插件)
文章目录 VSCode Error Lens 插件介绍**功能概述****开发背景****使用方法****适用场景** VSCode Error Lens 插件介绍 功能概述 Error Lens 是一款增强 VS Code 错误提示的扩展工具,通过 内联显示错误和警告信息,直接定位代码问题,提升开发…...
list_for_each_entry_safe 简介
list_for_each_entry_safe 是 Linux 内核中用于遍历链表的一个宏,特别适用于在遍历过程中可能需要删除链表节点的场景。它的设计保证了在删除当前节点时,不会影响后续节点的访问,从而实现安全的遍历。 定义 #define list_for_each_entry_sa…...
微软AutoGen高级功能——Memory
介绍 大家好,博主又来给大家分享知识了。这次又要给大家分享什么呢?哈哈。这次要给大家分享的是微软AutoGen框架的高级且重要的功能:Memory。在微软AutoGen中,Memory(记忆)是一个重要概念,它主要用于存储和管理智能体…...
【鸿蒙开发】第三十六章 状态管理 - V1V2混用和迁移指导
目录 1 自定义组件混用场景指导 1.1 概述 1.2 状态管理装饰器总览 状态管理V1的装饰器 状态管理V2的装饰器 状态管理装饰器支持的数据类型总览 1.3 限制条件 1.3.1 V1和V2的装饰器不允许混用 1.V1的自定义组件中不可以使用V2的装饰器 2.V2的自定义组件…...

轮子项目--消息队列的实现(3)
上一篇文章中我把一些关键的类以及表示出来,如何对这些类对应的对象进行管理呢?管理分为硬盘和内存上,硬盘又分为数据库(管理交换机,队列和绑定)和文件(管理消息),本文就…...

一文深入了解DeepSeek-R1:模型架构
本文深入探讨了 DeepSeek-R1 模型架构。让我们从输入到输出追踪 DeepSeek-R1 模型,以找到架构中的新发展和关键部分。DeepSeek-R1 基于 DeepSeek-V3-Base 模型架构。本文旨在涵盖其设计的所有重要方面。 📝 1. 输入上下文长度 DeepSeek-R1的输入上下文长…...
秘密信息嵌入到RGB通道的方式:分段嵌or完整嵌入各通道
目录 1. 将秘密信息分为三部分的理由 (1)均匀分布负载 (2)提高鲁棒性 (3)容量分配 2. 不将秘密信息分为三部分的情况 (1)嵌入容量 (2)视觉质量 &#…...
Ai人工智能的未来:趋势、挑战与机遇
Ai人工智能的未来:趋势、挑战与机遇 引言 人工智能(AI)已经成为当代科技发展的核心驱动力,其影响力渗透到各个行业,并塑造了我们未来的社会结构。无论是在医疗、金融、制造业,还是在自动驾驶、智能客服、…...
理解WebGPU 中的 GPUDevice :与 GPU 交互的核心接口
在 WebGPU 开发中, GPUDevice 是一个至关重要的对象,它是与 GPU 进行交互的核心接口。通过 GPUDevice ,开发者可以创建和管理 GPU 资源(如缓冲区、纹理、管线等),并提交命令缓冲区以执行渲染和计算任…...

Java 设计模式之桥接模式
文章目录 Java 设计模式之桥接模式概述UML代码实现 Java 设计模式之桥接模式 概述 桥接模式(Bridge):将抽象部分与它的实现部分分离,使它们都可以独立地变化。通过桥接模式,可以避免类爆炸问题,并提高系统的可扩展性。 UML 核心…...

机器学习(李宏毅)——GAN
一、前言 本文章作为学习2023年《李宏毅机器学习课程》的笔记,感谢台湾大学李宏毅教授的课程,respect!!! 不得不说GAN真是博大精深! 二、大纲 GAN问世基本思想原理剖析Tips of GANGAN的应用Cycle GANEva…...
QT无弹窗运行和只允许运行一个exe
最近做一个小功能,需要后台运行QT程序,无弹窗,并且只允许一个exe运行,不关闭程序,无法2次启动。 main.cpp #include "deleteshotcurveflie.h" #include <QApplication> #include <QSharedMemory&…...
<6>-MySQL表的增删查改
目录 一,create(创建表) 二,retrieve(查询表) 1,select列 2,where条件 三,update(更新表) 四,delete(删除表…...
DeepSeek 赋能智慧能源:微电网优化调度的智能革新路径
目录 一、智慧能源微电网优化调度概述1.1 智慧能源微电网概念1.2 优化调度的重要性1.3 目前面临的挑战 二、DeepSeek 技术探秘2.1 DeepSeek 技术原理2.2 DeepSeek 独特优势2.3 DeepSeek 在 AI 领域地位 三、DeepSeek 在微电网优化调度中的应用剖析3.1 数据处理与分析3.2 预测与…...

CocosCreator 之 JavaScript/TypeScript和Java的相互交互
引擎版本: 3.8.1 语言: JavaScript/TypeScript、C、Java 环境:Window 参考:Java原生反射机制 您好,我是鹤九日! 回顾 在上篇文章中:CocosCreator Android项目接入UnityAds 广告SDK。 我们简单讲…...

零基础在实践中学习网络安全-皮卡丘靶场(第九期-Unsafe Fileupload模块)(yakit方式)
本期内容并不是很难,相信大家会学的很愉快,当然对于有后端基础的朋友来说,本期内容更加容易了解,当然没有基础的也别担心,本期内容会详细解释有关内容 本期用到的软件:yakit(因为经过之前好多期…...
Xen Server服务器释放磁盘空间
disk.sh #!/bin/bashcd /run/sr-mount/e54f0646-ae11-0457-b64f-eba4673b824c # 全部虚拟机物理磁盘文件存储 a$(ls -l | awk {print $NF} | cut -d. -f1) # 使用中的虚拟机物理磁盘文件 b$(xe vm-disk-list --multiple | grep uuid | awk {print $NF})printf "%s\n"…...

短视频矩阵系统文案创作功能开发实践,定制化开发
在短视频行业迅猛发展的当下,企业和个人创作者为了扩大影响力、提升传播效果,纷纷采用短视频矩阵运营策略,同时管理多个平台、多个账号的内容发布。然而,频繁的文案创作需求让运营者疲于应对,如何高效产出高质量文案成…...
MySQL JOIN 表过多的优化思路
当 MySQL 查询涉及大量表 JOIN 时,性能会显著下降。以下是优化思路和简易实现方法: 一、核心优化思路 减少 JOIN 数量 数据冗余:添加必要的冗余字段(如订单表直接存储用户名)合并表:将频繁关联的小表合并成…...
根目录0xa0属性对应的Ntfs!_SCB中的FileObject是什么时候被建立的----NTFS源代码分析--重要
根目录0xa0属性对应的Ntfs!_SCB中的FileObject是什么时候被建立的 第一部分: 0: kd> g Breakpoint 9 hit Ntfs!ReadIndexBuffer: f7173886 55 push ebp 0: kd> kc # 00 Ntfs!ReadIndexBuffer 01 Ntfs!FindFirstIndexEntry 02 Ntfs!NtfsUpda…...
LLaMA-Factory 微调 Qwen2-VL 进行人脸情感识别(二)
在上一篇文章中,我们详细介绍了如何使用LLaMA-Factory框架对Qwen2-VL大模型进行微调,以实现人脸情感识别的功能。本篇文章将聚焦于微调完成后,如何调用这个模型进行人脸情感识别的具体代码实现,包括详细的步骤和注释。 模型调用步骤 环境准备:确保安装了必要的Python库。…...

归并排序:分治思想的高效排序
目录 基本原理 流程图解 实现方法 递归实现 非递归实现 演示过程 时间复杂度 基本原理 归并排序(Merge Sort)是一种基于分治思想的排序算法,由约翰冯诺伊曼在1945年提出。其核心思想包括: 分割(Divide):将待排序数组递归地分成两个子…...