26

ディスクに書き込めるように、GO で文字列配列をバイト配列に変換しようとしています。[]string文字列配列 ( ) をバイト配列 ( )にエンコードおよびデコードするための最適なソリューションは何[]byteですか?

[]byte(str)最初はバイト配列に必要な実際のサイズを取得し、次に各要素の長さと実際の文字列 ( ) を書き込むために、文字列配列を 2 回反復することを考えていました。

ソリューションは、それを逆に変換できる必要があります。から[]byte[]string

4

7 に答える 7

27

これが Go であるという事実を少し無視しましょう。最初に必要なのは、をマーシャリングするためのシリアル化形式です[]string

ここには多くのオプションがあります。独自にビルドすることも、ライブラリを使用することもできます。私は、あなたが独自のものを構築したくないと仮定し、シリアライゼーション形式がサポートするようにジャンプします。

すべての例で、data は[]stringファイル、fp は読み取り/書き込み先のファイルです。エラーは無視されています。関数の戻り値をチェックして、エラーを処理してください。

ゴブ

Gob は go のみのバイナリ形式です。文字列の数が増えると、比較的スペース効率が良くなるはずです。

enc := gob.NewEncoder(fp)
enc.Encode(data)

読み方もシンプル

var data []string
dec := gob.NewDecoder(fp)
dec.Decode(&data)

ゴブはシンプルで要点です。ただし、この形式は他の Go コードでのみ読み取り可能です。

ジェイソン

次はjsonです。Json は、あらゆる場所で使用される形式です。このフォーマットも同様に使いやすいです。

enc := json.NewEncoder(fp)
enc.Encode(data)

そして読むために:

var data []string
dec := json.NewDecoder(fp)
dec.Decode(&data)

XML

XML は、もう 1 つの一般的な形式です。ただし、オーバーヘッドがかなり高く、使いやすいものではありません。gob と json で行ったのと同じことができますが、適切な xml にはルート タグが必要です。この場合、ルート タグ「Strings」を使用しており、各文字列は「S」タグでラップされています。

type Strings struct {
    S []string
}

enc := xml.NewEncoder(fp)
enc.Encode(Strings{data})

var x Strings
dec := xml.NewDecoder(fp)
dec.Decode(&x)
data := x.S

CSV

CSVは他とは異なります。n 行で 1 つのレコードを使用するか、1 行で n レコードを使用するかの 2 つのオプションがあります。次の例では、n 個のレコードを使用しています。レコード一枚だとつまらない。それはあまりにも他のものに似ているでしょう。CSV は文字列のみを保持できます。

enc := csv.NewWriter(fp)
for _, v := range data {
    enc.Write([]string{v})
}
enc.Flush()

読むには:

var err error
var data string
dec := csv.NewReader(fp)
for err == nil {        // reading ends when an error is reached (perhaps io.EOF)
    var s []string

    s, err = dec.Read()
    if len(s) > 0 {
        data = append(data, s[0])
    }
}

どの形式を使用するかは好みの問題です。私が言及していない他の多くの可能なエンコーディングがあります。たとえば、bencode という外部ライブラリがあります。私は個人的に bencode が好きではありませんが、動作します。これは、bittorrent メタデータ ファイルで使用されるのと同じエンコーディングです。

独自のエンコーディングを作成したい場合は、encoding/binary から始めるのがよいでしょう。これにより、可能な限り最もコンパクトなファイルを作成できますが、努力する価値があるとはほとんど思いません.

于 2012-11-27T00:08:04.307 に答える
10

gob パッケージがこれを行いますhttp://godoc.org/encoding/gob

http://play.golang.org/p/e0FEZm-qiSで遊ぶ例

同じソースコードを以下に示します。

package main

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

func main() {
    // store to byte array
    strs := []string{"foo", "bar"}
    buf := &bytes.Buffer{}
    gob.NewEncoder(buf).Encode(strs)
    bs := buf.Bytes()
    fmt.Printf("%q", bs)

    // Decode it back
    strs2 := []string{}
    gob.NewDecoder(buf).Decode(&strs2)
    fmt.Printf("%v", strs2)
}
于 2012-11-26T21:47:44.490 に答える
2

問題を説明するために、 に変換し[]stringてから に戻します。簡単な解決策は次のとおりです。[]byte[]byte[]string

package main

import (
    "encoding/binary"
    "fmt"
)

const maxInt32 = 1<<(32-1) - 1

func writeLen(b []byte, l int) []byte {
    if 0 > l || l > maxInt32 {
        panic("writeLen: invalid length")
    }
    var lb [4]byte
    binary.BigEndian.PutUint32(lb[:], uint32(l))
    return append(b, lb[:]...)
}

func readLen(b []byte) ([]byte, int) {
    if len(b) < 4 {
        panic("readLen: invalid length")
    }
    l := binary.BigEndian.Uint32(b)
    if l > maxInt32 {
        panic("readLen: invalid length")
    }
    return b[4:], int(l)
}

func Decode(b []byte) []string {
    b, ls := readLen(b)
    s := make([]string, ls)
    for i := range s {
        b, ls = readLen(b)
        s[i] = string(b[:ls])
        b = b[ls:]
    }
    return s
}

func Encode(s []string) []byte {
    var b []byte
    b = writeLen(b, len(s))
    for _, ss := range s {
        b = writeLen(b, len(ss))
        b = append(b, ss...)
    }
    return b
}

func codecEqual(s []string) bool {
    return fmt.Sprint(s) == fmt.Sprint(Decode(Encode(s)))
}

func main() {
    var s []string
    fmt.Println("equal", codecEqual(s))
    s = []string{"", "a", "bc"}
    e := Encode(s)
    d := Decode(e)
    fmt.Println("s", len(s), s)
    fmt.Println("e", len(e), e)
    fmt.Println("d", len(d), d)
    fmt.Println("equal", codecEqual(s))
}

出力:

equal true
s 3 [ a bc]
e 19 [0 0 0 3 0 0 0 0 0 0 0 1 97 0 0 0 2 98 99]
d 3 [ a bc]
equal true
于 2013-05-16T11:34:43.407 に答える
1

PutUvarintUvarintを使用して、格納/取得し、いくつかに渡すためにlen(s)使用することをお勧めします。から既知の文字列の長さを使用して、を someに渡すことができます。[]byte(str)strio.WriterUvarintbuf := make([]byte, n)bufio.Reader

文字列配列の長さを全体に追加し、そのすべての項目に対して上記を繰り返します。全体を読み戻すことは、最初に外側の長さを読み取り、読み取った項目を n 回繰り返すことです。

于 2012-11-26T21:21:42.157 に答える
1

に変換[]stringする[]byte

var str = []string{"str1","str2"}
var x = []byte{}

for i:=0; i<len(str); i++{
    b := []byte(str[i])
    for j:=0; j<len(b); j++{
        x = append(x,b[j])
    }
}

に変換[]byteするstring

str := ""
var x = []byte{'c','a','t'}
for i := 0; i < len(x); i++ {
    str += string(x[i])
}
于 2013-05-14T20:34:09.893 に答える