Преобразовать массив int в байтовый массив, сжать его, а затем обратить его - PullRequest
1 голос
/ 09 июля 2019

У меня есть большой массив int, который я хочу сохранить в файловой системе.Насколько я понимаю, лучший способ сохранить что-то подобное - это использовать пакет gob , чтобы преобразовать его в байтовый массив и затем сжать его с помощью gzip .Когда мне это снова нужно, я переворачиваю процесс.Я уверен, что храню его правильно, однако восстановить его не удастся с помощью EOF.Короче говоря, у меня есть пример кода ниже, который демонстрирует проблему.(ссылка на игровую площадку здесь https://play.golang.org/p/v4rGGeVkLNh). Я не уверен, что gob необходим, однако, читая вокруг, кажется, что более эффективно хранить его в виде байтового массива, чем массива int, но это может быть не так. Спасибо!

package main

import (
    "bufio"
    "bytes"
    "compress/gzip"
    "encoding/gob"
    "fmt"
)

func main() {
    arry := []int{1, 2, 3, 4, 5}
    //now gob this
    var indexBuffer bytes.Buffer
    writer := bufio.NewWriter(&indexBuffer)
    encoder := gob.NewEncoder(writer)
    if err := encoder.Encode(arry); err != nil {
        panic(err)
    }
    //now compress it
    var compressionBuffer bytes.Buffer
    compressor := gzip.NewWriter(&compressionBuffer)
    compressor.Write(indexBuffer.Bytes())
    defer compressor.Close()
    //<--- I think all is good until here

    //now decompress it
    buf := bytes.NewBuffer(compressionBuffer.Bytes())
    fmt.Println("byte array before unzipping: ", buf.Bytes())
    if reader, err := gzip.NewReader(buf); err != nil {
        fmt.Println("gzip failed ", err)
        panic(err)
    } else {
        //now ungob it...
        var intArray []int
        decoder := gob.NewDecoder(reader)
        defer reader.Close()
        if err := decoder.Decode(&intArray); err != nil {
            fmt.Println("gob failed ", err)
            panic(err)
        }
        fmt.Println("final int Array content: ", intArray)
    }
}

1 Ответ

1 голос
/ 09 июля 2019

Вы используете bufio.Writer, который, как следует из его названия, буферизует записанных в него байтов.Это означает, что если вы используете его, вам нужно очистить , чтобы убедиться, что буферизованные данные попадают в базовый модуль записи:

writer := bufio.NewWriter(&indexBuffer)
encoder := gob.NewEncoder(writer)
if err := encoder.Encode(arry); err != nil {
    panic(err)
}
if err := writer.Flush(); err != nil {
    panic(err)
}

Хотя использование bufio.Writerсовершенно ненужно, так как вы уже записываете в буфер в памяти (bytes.Buffer), поэтому просто пропустите это и запишите непосредственно в bytes.Buffer (и вам даже не придется очищать):

var indexBuffer bytes.Buffer
encoder := gob.NewEncoder(&indexBuffer)
if err := encoder.Encode(arry); err != nil {
    panic(err)
}

Следующая ошибка заключается в том, как вы закрываете поток gzip:

defer compressor.Close()

Это отложенное закрытие произойдет только тогда, когда возвращается функция включения (функция main()), а нена секунду раньше.Но к тому времени вы уже хотели читать сжатые данные, но они все еще могут находиться во внутреннем кэше gzip.Writer, а не в compressionBuffer, поэтому вы, очевидно, не сможете прочитать сжатые данныеот compressionBuffer.Закройте поток gzip, не используя defer:

if err := compressor.Close(); err != nil {
    panic(err)
}

С этими изменениями вы запрограммируете запуск и вывод (попробуйте это на Go Playground ):

byte array before unzipping:  [31 139 8 0 0 0 0 0 0 255 226 249 223 200 196 200 244 191 137 129 145 133 129 129 243 127 19 3 43 19 11 27 7 23 32 0 0 255 255 110 125 126 12 23 0 0 0]
final int Array content:  [1 2 3 4 5]

В качестве примечания: buf := bytes.NewBuffer(compressionBuffer.Bytes()) - этот buf также совершенно не нужен, вы можете просто начать декодировать compressionBuffer, вы можете прочитать с него данные, которые были ранее записаны в него.

Как вы могли заметить, сжатые данные намного больше, чем исходные сжатые данные.Причин несколько: и потоки encoding/gob и compress/gzip имеют значительные издержки, и они (могут) только уменьшают ввод в большем масштабе (5 целых чисел неуточните это).

Пожалуйста, проверьте связанный вопрос: Эффективная Go сериализация структуры на диск

Для небольших массивов, вы также можете рассмотреть кодирование переменной длины, см. binary.PutVarint().

...