Golang序列化和反序列化

huangapple go评论82阅读模式
英文:

Golang serialize and deserialize back

问题

在Golang中,将结构体序列化和反序列化为字符串的最佳方法(完整性和性能)是什么?

例如,如果我有以下结构体:

type Session struct {
   Properties  map[string]interface{}
   Permissions []int64
}

我想将其存储在Redis中并取回。我已经尝试保存整数和字符串,这是可以的,但如何存储结构体对象呢?

conn := redisConnectors.Get()

// 设置示例
_, err := conn.Do(`SETEX`, `uid_key`, EXPIRE_SEC, user_id)
_, err = conn.Do(`SETEX`, `email_key`, EXPIRE_SEC, login_email)

// 获取示例
user_id, err := redis.Int64(conn.Do(`GET`, `uid_key`))
login_email, err := redis.String(conn.Do(`GET`, `email_key`))

你可以使用Golang的encoding/json包来将结构体序列化为字符串,然后再反序列化回结构体。这是一个示例代码:

import (
    "encoding/json"
    "github.com/garyburd/redigo/redis"
)

type Session struct {
   Properties  map[string]interface{}
   Permissions []int64
}

// 序列化结构体为字符串
func serialize(session Session) (string, error) {
    data, err := json.Marshal(session)
    if err != nil {
        return "", err
    }
    return string(data), nil
}

// 反序列化字符串为结构体
func deserialize(data string) (Session, error) {
    var session Session
    err := json.Unmarshal([]byte(data), &session)
    if err != nil {
        return Session{}, err
    }
    return session, nil
}

// 示例用法
session := Session{
    Properties: map[string]interface{}{
        "key1": "value1",
        "key2": 123,
    },
    Permissions: []int64{1, 2, 3},
}

// 序列化为字符串
serialized, err := serialize(session)
if err != nil {
    // 处理错误
}

// 存储到Redis
_, err = conn.Do(`SETEX`, `session_key`, EXPIRE_SEC, serialized)
if err != nil {
    // 处理错误
}

// 从Redis获取
serialized, err := redis.String(conn.Do(`GET`, `session_key`))
if err != nil {
    // 处理错误
}

// 反序列化为结构体
deserialized, err := deserialize(serialized)
if err != nil {
    // 处理错误
}

这样,你就可以将结构体序列化为字符串并存储在Redis中,然后再从Redis中获取字符串并反序列化回结构体。

英文:

What's the best way (completeness and performance) in Golang to serialize and deserialize a struct to string and vice versa?

for example, if I have this struct:

struct Session {
Properties map[string]interface{}
Permissions []int64
}

I want to store it on Redis and fetch it back. I have tried to save, int and string, it's fine, but how to store struct object?

conn := redisConnectors.Get()
// set example
_, err := conn.Do(`SETEX`, `uid_key`, EXPIRE_SEC, user_id)
_, err = conn.Do(`SETEX`, `email_key`, EXPIRE_SEC, login_email)
// get example
user_id, err := redis.Int64(conn.Do(`GET`, `uid_key`))
login_email, err := redis.String(conn.Do(`GET`, `email_key`))

答案1

得分: 43

使用gobbase64可以解决这个问题,例如:

import (
	"encoding/base64"
	"encoding/gob"
	"bytes"
)

type SX map[string]interface{}

// go二进制编码器
func ToGOB64(m SX) string {
	b := bytes.Buffer{}
	e := gob.NewEncoder(&b)
	err := e.Encode(m)
	if err != nil { fmt.Println(`failed gob Encode`, err) }
	return base64.StdEncoding.EncodeToString(b.Bytes())
}

// go二进制解码器
func FromGOB64(str string) SX {
	m := SX{}
	by, err := base64.StdEncoding.DecodeString(str)
	if err != nil { fmt.Println(`failed base64 Decode`, err); }
	b := bytes.Buffer{}
	b.Write(by)
	d := gob.NewDecoder(&b)
	err = d.Decode(&m)
	if err != nil { fmt.Println(`failed gob Decode`, err) }
	return m
}

当你需要序列化自定义的结构体或类型(例如Session结构体)时,只需添加以下代码:

func init() {
    gob.Register(SX{})
    gob.Register(Session{}) 
}

如果你想使用其他序列化格式(2020年)或者这个基准测试(2022年)来处理动态结构。

英文:

Using gob and base64 could solve the problem, for example:

import (
"encoding/base64"
"encoding/gob"
"bytes"
)
type SX map[string]interface{}
// go binary encoder
func ToGOB64(m SX) string {
b := bytes.Buffer{}
e := gob.NewEncoder(&b)
err := e.Encode(m)
if err != nil { fmt.Println(`failed gob Encode`, err) }
return base64.StdEncoding.EncodeToString(b.Bytes())
}
// go binary decoder
func FromGOB64(str string) SX {
m := SX{}
by, err := base64.StdEncoding.DecodeString(str)
if err != nil { fmt.Println(`failed base64 Decode`, err); }
b := bytes.Buffer{}
b.Write(by)
d := gob.NewDecoder(&b)
err = d.Decode(&m)
if err != nil { fmt.Println(`failed gob Decode`, err); }
return m
}

and when you need to serialize custom struct or type (for example Session struct), just add these lines:

func init() {
gob.Register(SX{})
gob.Register(Session{}) 
}

if you want to use other serialization format (2020) or this benchmark (2022) for dynamic structure

答案2

得分: 16

结构体的序列化通常使用encoding包。然而,这只适用于公共字段。如果你还需要序列化私有字段,可以参考这个答案作为替代方案。
你有几种编码选择(二进制、文本、像这个例子中的json结构体、xml等)。例如,项目cupcake/rdb使用encoding/binary来实现解析和编码RedisRDB文件格式(内存中存储的二进制表示)。
另一个例子是guregu/rediscache,一个用于在Redis中缓存数据的小型库。

英文:

Serialization of a struct generally uses the encoding package. However, that will work for public fields only. If you also need to serialize private fields, see this answer as an alternative.
You have several encoding choices (binary, text, json as in this example for a struct, xml, etc.). For example, the project cupcake/rdb uses encoding/binary to implement parsing and encoding of the Redis RDB file format (a binary representation of the in-memory store).
Another example is guregu/rediscache, a small library for caching data in Redis.

huangapple
  • 本文由 发表于 2015年1月19日 15:51:45
  • 转载请务必保留本文链接:https://go.coder-hub.com/28020070.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定