正文
go语言toyaml函数 go语言函数和方法
小程序:扫一扫查出行
【扫一扫了解最新限行尾号】
复制小程序
【扫一扫了解最新限行尾号】
复制小程序
Golang项目中引入yaml.v2配置文件
在Go语言项目中go语言toyaml函数,常用go语言toyaml函数的配置文件yaml、toml、json、xml、ini几种go语言toyaml函数,因为本章主要讲解yaml配置文件的使用方法,其他几种配置文件在这里就不展开了介绍了,大家有兴趣可以自行百度。
yaml文件的语法网上有很多的教程,大家自行百度,这里也推荐两个链接:
yaml文件解析使用的是github上第三方开源框架 gopkg.in/yaml.v2 ,下面详细介绍安装和使用的方法:
参考链接:
golang json:怎么替代yaml:
安装EasyDataTransform在Mac上就可以解决。
安装EasyDataTransform在Mac上,开始轻松的数据转换,将要显示重复项的Excel电子表格拖到EasyDataTransform上。将添加一个粉红色的输入项请注意右侧窗格中的JSON数据已自动“展平”到表格中。
您可以将右窗格中的Format下拉菜单设置为Long或Wide,具体取决于您希望表格具有更多行还是更多列,确保选择了粉红色的输入项,单击左窗格中的ToFile按钮,将出现一个窗口。设置新文件名和位置。选择YAML文件作为文件类型。添加并选择了一个绿色输出项。YAML文件会立即创建,无需“运行”任何内容您可以在右侧窗格中更改YAML文件编码。
C语言操作yaml配置文件通用操作工具
在go语言中使用viper之类的库很方便的处理yaml配置文件,但是在c语言中就比较麻烦,经过一番思索和借助强大的github,发现了一个libyaml c库,但是网上的例子都比较麻烦,而且比较繁琐,就想法作了一个相对比较容易配置的解析应用,可以简单地类似viper 的模式进行配置实现不同的配置文件读取。如你的配置文件很复杂请按格式修改KeyValue 全局变量,欢迎大家一起完善
库请自行下载 GitHub - yaml/libyaml: Canonical source repository for LibYAML
直接上代码
yaml示例文件
%YAML 1.1
---
mqtt:
subtopic: "Control/#"
pubtopic: "bbt"
qos: 1
serveraddress: "tcp://192.168.0.25:1883"
clientid: "kvm_test"
writelog: false
writetodisk: false
outputfile: "./receivedMessages.txt"
hearttime: 30
#ifndef __CONFIG_H__
#define __CONFIG_H__
#ifdef __cplusplus
extern "C" {
#endif
/************************/
/* Minimum YAML version */
/************************/
#define YAML_VERSION_MAJOR 1
#define YAML_VERSION_MINOR 1
#define STRUCT_TYPE_NAME 100
#define INT_TYPE_NAME 101
#define STRING_TYPE_NAME 102
#define BOOL_TYPE_NAME 103
#define FLOAT_TYPE_NAME 104
#define MAP_TYPE_NAME 105
#define LIST_TYPE_NAME 106
typedef struct{
char *key;
void *value;
int valuetype;
char *parent;
}KeyValue,*pKeyValue;
#ifdef __cplusplus
}
#endif
#endif
#include
#include
#include
#include
#include
#include
#include
#include "config.h"
typedef struct {
char *SUBTOPIC; //string `yaml:"subtopic" mapstructure:"subtopic"` //"topic1"
char *PUBTOPIC; //string `yaml:"pubtopic" mapstructure:"pubtopic"`
int QOS; //byte `yaml:"qos" mapstructure:"qos"` //1
char *SERVERADDRESS; //string `yaml:"serveraddress" mapstructure:"serveraddress"` //= "tcp://mosquitto:1883"
char *CLIENTID; //string `yaml:"clientid" mapstructure:"clientid"` //= "mqtt_subscriber"
int HEARTTIME; //int `yaml:"hearttime" mapstructure:"hearttime"`
// CommandLocalPath string `yam:"commanlocalpath"`
}mqttSection,*pmqttSection;
typedef struct {
mqttSection Mqtt;// `yaml:"mqtt" mapstructure:"mqtt"`
// KVM kvmSection `yaml:"kvm" mapstructure:"kvm"`
}ConfigT;
ConfigT config;
static KeyValue webrtcconfig[]={
{"mqtt",config,STRUCT_TYPE_NAME,NULL},
{"subtopic",(config.Mqtt.SUBTOPIC),STRING_TYPE_NAME,"mqtt"},
{"pubtopic",(config.Mqtt.PUBTOPIC),STRING_TYPE_NAME,"mqtt"},
{"qos",(config.Mqtt.QOS),INT_TYPE_NAME,"mqtt"},
{"serveraddress",(config.Mqtt.SERVERADDRESS),STRING_TYPE_NAME,"mqtt"},
{"clientid",(config.Mqtt.CLIENTID),STRING_TYPE_NAME,"mqtt"},
{"hearttime",(config.Mqtt.HEARTTIME),INT_TYPE_NAME,"mqtt"},
{NULL,NULL,0,NULL},
};
int printConfig(ConfigT * pconfig){
if(pconfig==NULL) return -1;
printf("mqtt:r ");
if(pconfig-Mqtt.SUBTOPIC!=NULL) {printf("subtopic: %sr ",pconfig-Mqtt.SUBTOPIC); }
if(pconfig-Mqtt.SUBTOPIC!=NULL) {printf("pubtopic: %sr ",pconfig-Mqtt.PUBTOPIC); }
printf("qos: %dr ",config.Mqtt.QOS);
if(pconfig-Mqtt.SERVERADDRESS!=NULL) {printf("serveraddress: %sr ",pconfig-Mqtt.SERVERADDRESS); }
if(pconfig-Mqtt.CLIENTID!=NULL) {printf("clientid: %sr ",pconfig-Mqtt.CLIENTID); }
printf("hearttime: %dr ",config.Mqtt.HEARTTIME);
}
int freeConfig(ConfigT * pconfig){
if(pconfig==NULL) return -1;
if(pconfig-Mqtt.SERVERADDRESS!=NULL) {free(pconfig-Mqtt.SERVERADDRESS); }
if(pconfig-Mqtt.CLIENTID!=NULL) {free(pconfig-Mqtt.CLIENTID); }
if(pconfig-Mqtt.SUBTOPIC!=NULL) {free(pconfig-Mqtt.SUBTOPIC); }
}
char currentkey[100];
void getvalue(yaml_event_t event,pKeyValue *ppconfigs){
char *value = (char *)event.data.scalar.value;
pKeyValue pconfig=*ppconfigs;
char *pstringname;
while(pconfig-key!=NULL){
if(currentkey[0]!=0){
if(!strcmp(currentkey,pconfig-key))
{
switch(pconfig-valuetype){
case STRING_TYPE_NAME:
pstringname=strdup(value);
printf("get string value %sr ",pstringname);
*((char**)pconfig-value)=pstringname;
memset(currentkey, 0, sizeof(currentkey));
break;
case INT_TYPE_NAME:
*((int*)(pconfig-value))=atoi(value);
memset(currentkey, 0, sizeof(currentkey));
break;
case BOOL_TYPE_NAME:
if(!strcmp(value,"true")) *((bool*)(pconfig-value))=true;
else *((bool*)(pconfig-value))=false;
memset(currentkey, 0, sizeof(currentkey));
break;
case FLOAT_TYPE_NAME:
*((float*)(pconfig-value))=atof(value);
memset(currentkey, 0, sizeof(currentkey));
break;
case STRUCT_TYPE_NAME:
case MAP_TYPE_NAME:
case LIST_TYPE_NAME:
memset(currentkey, 0, sizeof(currentkey));
strncpy(currentkey,value,strlen(value));
break;
default:
break;
}
break;
}
//continue;
}else{
if(!strcmp(value,pconfig-key)){
strncpy(currentkey,pconfig-key,strlen(pconfig-key));
break;
}
}
pconfig++;
}
}
int Load_YAML_Config( char *yaml_file, KeyValue *(configs[]) )
{
struct stat filecheck;
yaml_parser_t parser;
yaml_event_t event;
bool done = 0;
unsigned char type = 0;
unsigned char sub_type = 0;
if (stat(yaml_file, filecheck) != false )
{
printf("[%s, line %d] Cannot open configuration file '%s'! %s", __FILE__, __LINE__, yaml_file, strerror(errno) );
return -1;
}
FILE *fh = fopen(yaml_file, "r");
if (!yaml_parser_initialize(parser))
{
printf("[%s, line %d] Failed to initialize the libyaml parser. Abort!", __FILE__, __LINE__);
return -1;
}
if (fh == NULL)
{
printf("[%s, line %d] Failed to open the configuration file '%s' Abort!", __FILE__, __LINE__, yaml_file);
return -1;
}
memset(currentkey, 0, sizeof(currentkey));
/* Set input file */
yaml_parser_set_input_file(parser, fh);
while(!done)
{
if (!yaml_parser_parse(parser, event))
{
/* Useful YAML vars: parser.context_mark.line+1, parser.context_mark.column+1, parser.problem, parser.problem_mark.line+1, parser.problem_mark.column+1 */
printf( "[%s, line %d] libyam parse error at line %ld in '%s'", __FILE__, __LINE__, parser.problem_mark.line+1, yaml_file);
}
if ( event.type == YAML_DOCUMENT_START_EVENT )
{
//yaml file first line is version
//%YAML 1.1
//---
yaml_version_directive_t *ver = event.data.document_start.version_directive;
if ( ver == NULL )
{
printf( "[%s, line %d] Invalid configuration file. Configuration must start with "%%YAML 1.1"", __FILE__, __LINE__);
}
int major = ver-major;
int minor = ver-minor;
if (! (major == YAML_VERSION_MAJOR minor == YAML_VERSION_MINOR) )
{
printf( "[%s, line %d] Configuration has a invalid YAML version. Must be 1.1 or above", __FILE__, __LINE__);
return -1;
}
}
else if ( event.type == YAML_STREAM_END_EVENT )
{
done = true;
}
else if ( event.type == YAML_MAPPING_END_EVENT )
{
sub_type = 0;
}
else if ( event.type == YAML_SCALAR_EVENT )
{
getvalue(event,configs);
}
}
return 0;
}
int main(int argc, char *argv[]){
pKeyValue pconfig=webrtcconfig[0];
Load_YAML_Config("../../etc/kvmagent.yml",pconfig);
printConfig(config);
freeConfig(config);
}
34.Go YAML
YAML是一种流行的格式,用于以人类友好的格式序列化数据, 类似JSON但更易于阅读。
由于其表达能力和可读性,YAML作为配置文件的格式很受欢迎。
它也用于更复杂的场景中,例如推动Ansible服务器自动化。
标准库中没有用于处理YAML格式的软件包,但是社区库包括gopkg.in/yaml.v2
将YAML文件读取到Go结构中:
YAML:
YAML解码与JSON解码非常相似。
如果你知道YAML文件的结构,则可以定义映射该结构的结构,并将指向顶级结构的结构的指针传递给yaml.Decoder.Decode()函数(或从[]进行解码的yaml.Unmarshal())。 字节片)。
YAML解码器在结构字段名称和YAML文件中的名称之间进行智能映射,以便 YAML中的名称值被解码为结构中的字段名称。
最好使用yaml struct标签创建显式映射。 我仅在示例中省略了它们,以说明未指定它们时的行为。
将struct写入YAML文件:
yaml.Marshal将interface {}作为参数。 可以传递任何Go值,并将其类型包装到interface {}中。
Marshaller将使用反射检查传递的值并将其编码为YAML字符串。
在序列化结构时,仅对导出的字段(其名称以大写字母开头)进行序列化/反序列化。
在我们的示例中,未对fullName进行序列化。
结构被序列化为YAML字典。 默认情况下,字典键与结构字段名称相同。
结构字段名称在字典键名称下序列化。
我们可以提供带有struct标签的自定义映射。
我们可以将任意的struct标签字符串附加到struct字段。
yaml:“ age”指示YAML编码器/解码器将名称age用于表示字段Age的字典关键字。
序列化结构时,将值和指针传递给它会产生相同的结果。
传递指针效率更高,因为按值传递会创建不必要的副本。
golangci-line 工具介绍
在 ci 过程中,经常有一些可以通过静态分析或者白盒检测去避免一些问题以及规范代码格式!使用Go语言一般是使用 golangci-line 作为代码检测工具!
参考官网:
安装: curl-sSfL | sh -s -- -b $(go env GOPATH)/bin v1.43.0
版本信息: golangci-lint--version
目前我司是自己二开的 golangci-line,所以这里使用的开源版本,其实大同小异,就是开发了一些插件!
这个就是一个工具,集成了各类自动检测代码的工具,所以不需要本地安装太多的工具,只需要这个工具即可!
由于它需要一个go的项目,这里以我自己的项目去介绍, 项目地址:,如果有同学想自己尝试下可以直接下载我这个项目!项目也比较规范!
其实执行 golangci-lint run-h 就可以获取以下帮助
例如我经常使用的: 我日常就是开启format功能!
1、默认使用的插件
2、默认没用的
3、presets 分类:
具体可以参考我的:
主要是做一些 无用代码检测,简化代码,格式化代码!然后执行 golangci-lint run --fix 即可
Golang kafka简述和操作(sarama同步异步和消费组)
一、Kafka简述
1. 为什么需要用到消息队列
异步:对比以前的串行同步方式来说,可以在同一时间做更多的事情,提高效率;
解耦:在耦合太高的场景,多个任务要对同一个数据进行操作消费的时候,会导致一个任务的处理因为另一个任务对数据的操作变得及其复杂。
缓冲:当遇到突发大流量的时候,消息队列可以先把所有消息有序保存起来,避免直接作用于系统主体,系统主题始终以一个平稳的速率去消费这些消息。
2.为什么选择kafka呢?
这没有绝对的好坏,看个人需求来选择,我这里就抄了一段他人总结的的优缺点,可见原文
kafka的优点:
1.支持多个生产者和消费者2.支持broker的横向拓展3.副本集机制,实现数据冗余,保证数据不丢失4.通过topic将数据进行分类5.通过分批发送压缩数据的方式,减少数据传输开销,提高吞高量6.支持多种模式的消息7.基于磁盘实现数据的持久化8.高性能的处理信息,在大数据的情况下,可以保证亚秒级的消息延迟9.一个消费者可以支持多种topic的消息10.对CPU和内存的消耗比较小11.对网络开销也比较小12.支持跨数据中心的数据复制13.支持镜像集群
kafka的缺点:
1.由于是批量发送,所以数据达不到真正的实时2.对于mqtt协议不支持3.不支持物联网传感数据直接接入4.只能支持统一分区内消息有序,无法实现全局消息有序5.监控不完善,需要安装插件6.需要配合zookeeper进行元数据管理7.会丢失数据,并且不支持事务8.可能会重复消费数据,消息会乱序,可用保证一个固定的partition内部的消息是有序的,但是一个topic有多个partition的话,就不能保证有序了,需要zookeeper的支持,topic一般需要人工创建,部署和维护一般都比mq高
3. Golang 操作kafka
3.1. kafka的环境
网上有很多搭建kafka环境教程,这里就不再搭建,就展示一下kafka的环境,在kubernetes上进行的搭建,有需要的私我,可以发yaml文件
3.2. 第三方库
github.com/Shopify/sarama // kafka主要的库*github.com/bsm/sarama-cluster // kafka消费组
3.3. 消费者
单个消费者
funcconsumer(){varwg sync.WaitGroup consumer, err := sarama.NewConsumer([]string{"172.20.3.13:30901"},nil)iferr !=nil{ fmt.Println("Failed to start consumer: %s", err)return} partitionList, err := consumer.Partitions("test0")//获得该topic所有的分区iferr !=nil{ fmt.Println("Failed to get the list of partition:, ", err)return}forpartition :=rangepartitionList { pc, err := consumer.ConsumePartition("test0",int32(partition), sarama.OffsetNewest)iferr !=nil{ fmt.Println("Failed to start consumer for partition %d: %s\n", partition, err)return} wg.Add(1)gofunc(sarama.PartitionConsumer){//为每个分区开一个go协程去取值formsg :=rangepc.Messages() {//阻塞直到有值发送过来,然后再继续等待fmt.Printf("Partition:%d, Offset:%d, key:%s, value:%s\n", msg.Partition, msg.Offset,string(msg.Key),string(msg.Value)) }deferpc.AsyncClose() wg.Done() }(pc) } wg.Wait()}funcmain(){ consumer()}
消费组
funcconsumerCluster(){ groupID :="group-1"config := cluster.NewConfig() config.Group.Return.Notifications =trueconfig.Consumer.Offsets.CommitInterval =1* time.Second config.Consumer.Offsets.Initial = sarama.OffsetNewest//初始从最新的offset开始c, err := cluster.NewConsumer(strings.Split("172.20.3.13:30901",","),groupID, strings.Split("test0",","), config)iferr !=nil{ glog.Errorf("Failed open consumer: %v", err)return}deferc.Close()gofunc(c *cluster.Consumer){ errors := c.Errors() noti := c.Notifications()for{select{caseerr := -errors: glog.Errorln(err)case-noti: } } }(c)formsg :=rangec.Messages() { fmt.Printf("Partition:%d, Offset:%d, key:%s, value:%s\n", msg.Partition, msg.Offset,string(msg.Key),string(msg.Value)) c.MarkOffset(msg,"")//MarkOffset 并不是实时写入kafka,有可能在程序crash时丢掉未提交的offset}}funcmain(){goconsumerCluster()}
3.4. 生产者
同步生产者
packagemainimport("fmt""github.com/Shopify/sarama")funcmain(){ config := sarama.NewConfig() config.Producer.RequiredAcks = sarama.WaitForAll//赋值为-1:这意味着producer在follower副本确认接收到数据后才算一次发送完成。config.Producer.Partitioner = sarama.NewRandomPartitioner//写到随机分区中,默认设置8个分区config.Producer.Return.Successes =truemsg := sarama.ProducerMessage{} msg.Topic =`test0`msg.Value = sarama.StringEncoder("Hello World!") client, err := sarama.NewSyncProducer([]string{"172.20.3.13:30901"}, config)iferr !=nil{ fmt.Println("producer close err, ", err)return}deferclient.Close() pid, offset, err := client.SendMessage(msg)iferr !=nil{ fmt.Println("send message failed, ", err)return} fmt.Printf("分区ID:%v, offset:%v \n", pid, offset)}
异步生产者
funcasyncProducer(){ config := sarama.NewConfig() config.Producer.Return.Successes =true//必须有这个选项config.Producer.Timeout =5* time.Second p, err := sarama.NewAsyncProducer(strings.Split("172.20.3.13:30901",","), config)deferp.Close()iferr !=nil{return}//这个部分一定要写,不然通道会被堵塞gofunc(p sarama.AsyncProducer){ errors := p.Errors() success := p.Successes()for{select{caseerr := -errors:iferr !=nil{ glog.Errorln(err) }case-success: } } }(p)for{ v :="async: "+ strconv.Itoa(rand.New(rand.NewSource(time.Now().UnixNano())).Intn(10000)) fmt.Fprintln(os.Stdout, v) msg := sarama.ProducerMessage{ Topic: topics, Value: sarama.ByteEncoder(v), } p.Input() - msg time.Sleep(time.Second *1) }}funcmain(){goasyncProducer()select{ }}
3.5. 结果展示-
同步生产打印:
分区ID:0,offset:90
消费打印:
Partition:0,Offset:90,key:,value:Hello World!
异步生产打印:
async:7272async:7616async:998
消费打印:
Partition:0,Offset:91,key:,value:async:7272Partition:0,Offset:92,key:,value:async:7616Partition:0,Offset:93,key:,value:async:998
关于go语言toyaml函数和go语言函数和方法的介绍到此就结束了,不知道你从中找到你需要的信息了吗 ?如果你还想了解更多这方面的信息,记得收藏关注本站。