Encode array to base64 in go

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

Encode array to base64 in go

问题

这是我开发的一个函数的完整代码:

package main

import (
    "database/sql"
    "log"
    "encoding/xml"
    "github.com/gin-gonic/gin" //golang frameworks
    _ "github.com/go-sql-driver/mysql"
    "gopkg.in/gorp.v1"        //work with database(mysql, etc.)
)

type Genre struct {
    Title string `xml:"genre"`
}

type GenreArray struct {
    Auth_state int `xml:"auth_state"`
    Count int64 `xml:"count"`
    Item genreAPI `xml:"item"`
}

type UserPass struct {
    Username string `xml:"username"`
    Password string `xml:"password"`
}

type ErrorMessage struct {
    XMLName xml.Name `xml:"error"`
    Error string `xml:"error_code"`
    Message string `xml:"message"`
}

type Auth struct {
    XMLName xml.Name `xml:"config"`
    Nas_SharingEmpty  int `xml:"nas_sharing>auth_state"`
}

type ConfigGenre struct {
    XMLName xml.Name `xml:"config"`
    Nas_Sharing  GenreArray `xml:"nas_sharing"`
}

type genreAPI []Genre

var dbmap = initDb()

func initDb() *gorp.DbMap {

    db, err := sql.Open("mysql", "root@tcp(localhost:3306)/mymusic")
    checkErr(err, "sql.Open failed")
    dbmap := &gorp.DbMap{Db: db, Dialect: gorp.MySQLDialect{"InnoDB", "UTF8"}}

    return dbmap
}

func checkErr(err error, msg string) {
    if err != nil {
        log.Fatalln(msg, err)
    }
}

func main() {
    r := gin.Default()
    r.POST("/nas_sharing", myMusicXML)
    r.Run(":9999")
}

func myMusicXML(c *gin.Context) {

    c.Request.ParseForm()
    cmd := c.Request.Form.Get("cmd")
    usernamepost := c.Request.Form.Get("user")
    passwordpost := c.Request.Form.Get("passwd")

    if cmd == "36" {
    //Music Genre List API

        var genre []Genre
        var userpass []UserPass
        var count int64
        var countAuth int64

        //Query the post username and password
        _, errAuth := dbmap.Select(&userpass, "SELECT username, password FROM user WHERE username=? and password=?", usernamepost, passwordpost)

        //Check if post username and password exist
        countAuth, errAuth = dbmap.SelectInt("select count(*) FROM user WHERE username=? and password=?", usernamepost, passwordpost)
        if countAuth == 0 {
            //If no rows detected, output a message
            c.XML(404, Auth{Nas_SharingEmpty: 0})
        }else{
            //Check if query is valid
            if errAuth == nil {
                log.Println("auth_state :", countAuth)
            }else{
                c.XML(404, gin.H{"error": "sql query error found"})
            }
    
            //Query genre list
            _, err := dbmap.Select(&genre, "SELECT Title FROM genre_cntr_tbl")
    
            //Count genres
            count, err = dbmap.SelectInt("select count(*) FROM genre_cntr_tbl")
            if count == 0 {
                //If no rows detected, output a message
                c.XML(404, ErrorMessage{Error:"404", Message: "no genre found"})
            }else{
                //Check if query is valid
                if err == nil {
                    log.Println("Genres :", genre)
                    c.XML(200, ConfigGenre{Nas_Sharing: GenreArray{Auth_state: 1, Count: count, Item: genre,}})
                }else{
                    c.XML(404, gin.H{"error": "sql query error found"})
                }
            }
        }
    }else{
        c.XML(404, ErrorMessage{Error:"404", Message: "command not found"})
    }
}

这是我的输出结果:

<config>
<nas_sharing>
    <auth_state>1</auth_state>
    <count>8</count>
    <item>
        <genre>Pop</genre>
    </item>
    <item>
        <genre>Rock</genre>
    </item>
    <item>
        <genre>Dance</genre>
    </item>
    <item>
        <genre>Opera</genre>
    </item>
    <item>
        <genre>Techno</genre>
    </item>
    <item>
        <genre>Hip Hop</genre>
    </item>
    <item>
        <genre>Jazz</genre>
    </item>
    <item>
        <genre>Reggae</genre>
    </item>
</nas_sharing>
</config>

这是我输出到日志中的 genre 值(注意:它来自数据库):

Genres : [{Pop} {Rock} {Dance} {Opera} {Techno} {Hiphop} {Jazz} {Reggae}]

然而,我想将输出转换为 base64 格式。这是一个将数据编码为 base64 的示例代码,但是给定的数据是 string,不像我开发的那个来自数组。我该如何实现这个输出?

data := "/MyMusic/images/_albums/albums_nophoto.png"
sEnc := b64.StdEncoding.EncodeToString([]byte(data))
fmt.Println(sEnc)

这是我期望的输出:

<config>
<nas_sharing>
    <auth_state>1</auth_state>
    <count>8</count>
    <item>
        <genre>UG9w</genre>
    </item>
    <item>
        <genre>Um9jaw==</genre>
    </item>
    <item>
        <genre>RGFuY2U=</genre>
    </item>
    <item>
        <genre>T3BlcmE=</genre>
    </item>
    <item>
        <genre>VGVjaG5v</genre>
    </item>
    etc...
英文:

Here is my complete code for a function I develop:

package main
import (
&quot;database/sql&quot;
&quot;log&quot;
&quot;encoding/xml&quot;
&quot;github.com/gin-gonic/gin&quot; //golang frameworks
_ &quot;github.com/go-sql-driver/mysql&quot;
&quot;gopkg.in/gorp.v1&quot;        //work with database(mysql, etc.)
)
type Genre struct {
Title string `xml:&quot;genre&quot;`
}
type GenreArray struct {
Auth_state int `xml:&quot;auth_state&quot;`
Count int64 `xml:&quot;count&quot;`
Item genreAPI `xml:&quot;item&quot;`
}
type UserPass struct {
Username string `xml:&quot;username&quot;`
Password string `xml:&quot;password&quot;`
}
type ErrorMessage struct {
XMLName xml.Name `xml:&quot;error&quot;`
Error string `xml:&quot;error_code&quot;`
Message string `xml:&quot;message&quot;`
}
type Auth struct {
XMLName xml.Name `xml:&quot;config&quot;`
Nas_SharingEmpty  int `xml:&quot;nas_sharing&gt;auth_state&quot;`
}
type ConfigGenre struct {
XMLName xml.Name `xml:&quot;config&quot;`
Nas_Sharing  GenreArray `xml:&quot;nas_sharing&quot;`
}
type genreAPI []Genre
var dbmap = initDb()
func initDb() *gorp.DbMap {
db, err := sql.Open(&quot;mysql&quot;, &quot;root@tcp(localhost:3306)/mymusic&quot;)
checkErr(err, &quot;sql.Open failed&quot;)
dbmap := &amp;gorp.DbMap{Db: db, Dialect: gorp.MySQLDialect{&quot;InnoDB&quot;, &quot;UTF8&quot;}}
return dbmap
}
func checkErr(err error, msg string) {
if err != nil {
log.Fatalln(msg, err)
}
}
func main() {
r := gin.Default()
r.POST(&quot;/nas_sharing&quot;, myMusicXML)
r.Run(&quot;:9999&quot;)
}
func myMusicXML(c *gin.Context) {
c.Request.ParseForm()
cmd := c.Request.Form.Get(&quot;cmd&quot;)
usernamepost := c.Request.Form.Get(&quot;user&quot;)
passwordpost := c.Request.Form.Get(&quot;passwd&quot;)
if cmd == &quot;36&quot; {
//Music Genre List API
var genre []Genre
var userpass []UserPass
var count int64
var countAuth int64
//Query the post username and password
_, errAuth := dbmap.Select(&amp;userpass, &quot;SELECT username, password FROM user WHERE username=? and password=?&quot;, usernamepost, passwordpost)
//Check if post username and password exist
countAuth, errAuth = dbmap.SelectInt(&quot;select count(*) FROM user WHERE username=? and password=?&quot;, usernamepost, passwordpost)
if countAuth == 0 {
//If no rows detected, output a message
c.XML(404, Auth{Nas_SharingEmpty: 0})
}else{
//Check if query is valid
if errAuth == nil {
log.Println(&quot;auth_state :&quot;, countAuth)
}else{
c.XML(404, gin.H{&quot;error&quot;: &quot;sql query error found&quot;})
}
//Query genre list
_, err := dbmap.Select(&amp;genre, &quot;SELECT Title FROM genre_cntr_tbl&quot;)
//Count genres
count, err = dbmap.SelectInt(&quot;select count(*) FROM genre_cntr_tbl&quot;)
if count == 0 {
//If no rows detected, output a message
c.XML(404, ErrorMessage{Error:&quot;404&quot;, Message: &quot;no genre found&quot;})
}else{
//Check if query is valid
if err == nil {
log.Println(&quot;Genres :&quot;, genre)
c.XML(200, ConfigGenre{Nas_Sharing: GenreArray{Auth_state: 1, Count: count, Item: genre,}})
}else{
c.XML(404, gin.H{&quot;error&quot;: &quot;sql query error found&quot;})
}
}
}
}else{
c.XML(404, ErrorMessage{Error:&quot;404&quot;, Message: &quot;command not found&quot;})
}
}

And here is the output:

&lt;config&gt;
&lt;nas_sharing&gt;
&lt;auth_state&gt;1&lt;/auth_state&gt;
&lt;count&gt;8&lt;/count&gt;
&lt;item&gt;
&lt;genre&gt;Pop&lt;/genre&gt;
&lt;/item&gt;
&lt;item&gt;
&lt;genre&gt;Rock&lt;/genre&gt;
&lt;/item&gt;
&lt;item&gt;
&lt;genre&gt;Dance&lt;/genre&gt;
&lt;/item&gt;
&lt;item&gt;
&lt;genre&gt;Opera&lt;/genre&gt;
&lt;/item&gt;
&lt;item&gt;
&lt;genre&gt;Techno&lt;/genre&gt;
&lt;/item&gt;
&lt;item&gt;
&lt;genre&gt;Hip Hop&lt;/genre&gt;
&lt;/item&gt;
&lt;item&gt;
&lt;genre&gt;Jazz&lt;/genre&gt;
&lt;/item&gt;
&lt;item&gt;
&lt;genre&gt;Reggae&lt;/genre&gt;
&lt;/item&gt;
&lt;/nas_sharing&gt;

</config>

Here is the value of genre of my output to log(note: It came from a database):

Genres : [{Pop} {Rock} {Dance} {Opera} {Techno} {Hiphop} {Jazz} {Reggae}]  

However, I would like to convert the output to base64 format. Here's a sample code for encoding to base64 but the data given to this is string unlike the one I develop that comes from an array. How could I achieve that output?

data := &quot;/MyMusic/images/_albums/albums_nophoto.png&quot;
sEnc := b64.StdEncoding.EncodeToString([]byte(data))
fmt.Println(sEnc)

Here is what output I expected

&lt;config&gt;
&lt;nas_sharing&gt;
&lt;auth_state&gt;1&lt;/auth_state&gt;
&lt;count&gt;8&lt;/count&gt;
&lt;item&gt;
&lt;genre&gt;UG9w&lt;/genre&gt;
&lt;/item&gt;
&lt;item&gt;
&lt;genre&gt;Um9jaw==&lt;/genre&gt;
&lt;/item&gt;
&lt;item&gt;
&lt;genre&gt;RGFuY2U=&lt;/genre&gt;
&lt;/item&gt;
&lt;item&gt;
&lt;genre&gt;T3BlcmE=&lt;/genre&gt;
&lt;/item&gt;
&lt;item&gt;
&lt;genre&gt;VGVjaG5v&lt;/genre&gt;
&lt;/item&gt;
etc...

答案1

得分: 3

[]string编码为Base64格式

Base64是一种编码方式,用于将任意字节序列转换为文本,使用一组小而明确定义的字符。

因此,您需要决定/想出一种将[]string数组或切片转换为字节序列的方法。

一种简单方便的方法是将[]string转换为JSON文本,这也会处理转义字符串中的引号&quot;。可以使用您描述的方法轻松地对结果string进行编码:

genre := []string{"Pop", "Rock", "Dance", "Opera", "Techno", "Hiphop", "Jazz", "Reggae"}

data, _ := json.Marshal(&genre)
fmt.Println(string(data))
sEnc := base64.StdEncoding.EncodeToString(data)
fmt.Println(sEnc)

输出(在Go Playground上尝试):

["Pop","Rock","Dance","Opera","Techno","Hiphop","Jazz","Reggae"]
WyJQb3AiLCJSb2NrIiwiRGFuY2UiLCJPcGVyYSIsIlRlY2hubyIsIkhpcGhvcCIsIkphenoiLCJSZWdnYWUiXQ==

解码

有了这样的Base64结果,您可以这样解码:

data2, err := base64.StdEncoding.DecodeString(sEnc)
if err != nil {
    panic(err)
}
var genre2 []string
if err = json.Unmarshal(data2, &genre2); err != nil {
    panic(err)
}
fmt.Println(genre2)

输出:

[Pop Rock Dance Opera Techno Hiphop Jazz Reggae]

注意:

当然,您可以选择任何其他转换方式将[]string转换为字节序列。您可以将其转换为XML,或使用encoding/binary或其他任何方式。我选择JSON是因为它是一行代码,紧凑,快速,并且几乎在每种编程语言中都受支持,因此如果另一个程序需要解码它,这不会成为问题。

使单独的string字段显示为Base64

您可以通过在类型(或封闭的struct)上实现Marshaler接口来实现此目的,示例如下:

func (g *Genre) MarshalXML(e *xml.Encoder, start xml.StartElement) error {
    g2 := *g
    g2.Title = base64.StdEncoding.EncodeToString([]byte(g.Title))
    return e.EncodeElement(g2, start)
}

基本上,这将创建Genre的副本,将副本的Title字段值更改为其原始值的Base64表示,并对此副本进行编码。

输出(部分),在Go Playground上尝试:

<GenreArray>
    <item>
        <genre>UG9w</genre>
    </item>
    <item>
        <genre>Um9jaw==</genre>
    </item>
</GenreArray>
英文:

Foreword: The first section answers the original question (encode array to Base64). If you just want individual string fields to appear as Base64 strings in the output, see the 2nd section.


Encoding a []string into Base64 format

Base64 is an encoding, a function used to convert an arbitrary sequence of bytes to a text using a small, well defined set of characters.

So you have to decide / come up with a way to convert your []string array or slice to a sequence of bytes.

An easy and convenient way is to convert your []string to JSON text which will also take care of escaping strings having a quotation mark &quot; for example. The result string can be easily encoded using the method you described:

genre := []string{&quot;Pop&quot;, &quot;Rock&quot;, &quot;Dance&quot;, &quot;Opera&quot;, &quot;Techno&quot;, &quot;Hiphop&quot;, &quot;Jazz&quot;, &quot;Reggae&quot;}
data, _ := json.Marshal(&amp;genre)
fmt.Println(string(data))
sEnc := base64.StdEncoding.EncodeToString(data)
fmt.Println(sEnc)

Output (try it on the Go Playground):

[&quot;Pop&quot;,&quot;Rock&quot;,&quot;Dance&quot;,&quot;Opera&quot;,&quot;Techno&quot;,&quot;Hiphop&quot;,&quot;Jazz&quot;,&quot;Reggae&quot;]
WyJQb3AiLCJSb2NrIiwiRGFuY2UiLCJPcGVyYSIsIlRlY2hubyIsIkhpcGhvcCIsIkphenoiLCJSZWdnYWUiXQ==

Decoding

Having such Base64 result, you can decode it like this:

data2, err := base64.StdEncoding.DecodeString(sEnc)
if err != nil {
panic(err)
}
var genre2 []string
if err = json.Unmarshal(data2, &amp;genre2); err != nil {
panic(err)
}
fmt.Println(genre2)

Output:

[Pop Rock Dance Opera Techno Hiphop Jazz Reggae]

Notes:

Of course you may choose any other transformations to convert []string to a byte sequence. You could convert it to XML, or using the encoding/binary or anything else. I chose JSON because it is a one-liner, compact, fast, and is supported in almost every programming language, so it won't be a problem if another program has to decode it.

Making individual string fields to appear as Base64

You can do this by implementing the Marshaler interface on the type (or enclosing struct) like this:

func (g *Genre) MarshalXML(e *xml.Encoder, start xml.StartElement) error {
g2 := *g
g2.Title = base64.StdEncoding.EncodeToString([]byte(g.Title))
return e.EncodeElement(g2, start)
}

Basically what this does is creates a copy of Genre, changes the value of the Title field (of the copy) to the Base64 representation of its original value and encodes this copy.

Output (partial), try it on the Go Playground:

&lt;GenreArray&gt;
&lt;item&gt;
&lt;genre&gt;UG9w&lt;/genre&gt;
&lt;/item&gt;
&lt;item&gt;
&lt;genre&gt;Um9jaw==&lt;/genre&gt;
&lt;/item&gt;
&lt;/GenreArray&gt;

huangapple
  • 本文由 发表于 2015年6月10日 13:41:48
  • 转载请务必保留本文链接:https://go.coder-hub.com/30747956.html
匿名

发表评论

匿名网友

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

确定