Подтвердить что ты не робот

Преобразовать [] строку в [] байт

Я хочу преобразовать строковый массив в массив байтов в GO, чтобы записать его на диск. Что является оптимальным решением для кодирования и декодирования массива строк ([]string) в массив байтов ([]byte)?

Я думал об итерации строкового массива дважды, сначала для получения фактического размера, необходимого для массива байтов, а затем второго для записи длины и фактической строки ([]byte(str)) для каждого элемента.

Решение должно иметь возможность конвертировать его в другую сторону; от []byte до a []string.

4b9b3361

Ответ 1

Давайте проигнорируем тот факт, что это Go на секунду. Первое, что вам нужно, это формат сериализации для маршализации []string в.

Здесь много вариантов. Вы можете создать свой собственный или использовать библиотеку. Я собираюсь предположить, что вы не хотите создавать свои собственные и перейти к форматам сериализации, поддерживаемым.

Во всех примерах данные являются []string, а fp - это файл, который вы читаете/записываете. Ошибки игнорируются, проверяйте возвращаемые функции для обработки ошибок.

Капля

Gob - это только двоичный формат. Он должен быть относительно эффективным по площади, поскольку количество строк увеличивается.

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

Чтение также прост

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

Гоб прост и близок к точке. Тем не менее, формат доступен только для чтения с другим кодом Go.

Json

Далее json. Json - это формат, используемый практически везде. Этот формат так же прост в использовании.

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

И для чтения:

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

XML

XML - еще один распространенный формат. Тем не менее, он имеет довольно высокие накладные расходы и не так прост в использовании. Хотя вы могли бы просто сделать то же самое, что и для gob и json, для правильного xml требуется корневой тег. В этом случае мы используем корневой тег "Строки", и каждая строка обернута тегом "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 строками или n записей с 1 строкой. В следующем примере используются 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.

Если вы хотите создать свою собственную кодировку, кодировка/бинар - это хорошее место для начала. Это позволит вам сделать максимально компактный файл, но вряд ли это стоит усилий.

Ответ 2

Пакет 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)
}

Ответ 3

Я бы предложил использовать PutUvarint и Uvarint для сохранения/извлечения len(s) и с помощью []byte(str) передать str в некоторый io.Writer. С длиной строки, известной из Uvarint, можно buf := make([]byte, n) и передать buf в некоторый io.Reader.

Подготовьте все это с длиной массива строк и повторите описанное выше для всех своих элементов. Чтение всего назад снова считывает первую внешнюю длину и повторяет n-раз, когда элемент читается.

Ответ 4

Чтобы проиллюстрировать проблему, преобразуйте []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

Ответ 5

для преобразования []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])
}