#go #gzip
#Вперед #gzip
Вопрос:
У меня есть строка, которая содержит сжатую строку gzip, поэтому заголовков файлов нет, стандартная compress/gzip
библиотека выдает ошибку gzip: invalid header
Как я могу распаковать сжатую строку gzip в go?
Это то, что я пытаюсь
nbody := "eNorTk0uSi0BAAjRAoc="
rdata := strings.NewReader(nbody)
r,err := gzip.NewReader(rdata)
log.Println(r)
if err != nil {
log.Fatal(err)
}
s, _ := ioutil.ReadAll(r)
fmt.Println(string(s))
Комментарии:
1.
eNorTk0uSi0BAAjRAoc=
— это не «строка gzip». Это закодировано в zlib (zlib — это не gzip, также это в основном просто другой заголовок перед закодированным в deflate содержимым), а затем дополнительно кодируется в base64, поэтому вам нужно сначала декодировать его из base64, а затем использовать декомпрессию zlib, а не декомпрессию gzip.2. Можем ли мы каким-то образом изменить заголовок этого вопроса, чтобы он не отображался в поиске Google?
3. Можно ли полностью удалить этот вопрос или что-то в этом роде? Это не gzip
Ответ №1:
Поскольку этот вопрос постоянно появляется в Google, если у вас есть реальные данные, закодированные в gzip, в строке, и вы хотите их декодировать, вот как вы это сделаете:
import "compress/gzip";
import "bytes";
import "io/ioutil";
...
original := "gzipencodeddata";
reader := bytes.NewReader([]byte(original))
gzreader, e1 := gzip.NewReader(reader);
if(e1 != nil){
fmt.Println(e1); // Maybe panic here, depends on your error handling.
}
output, e2 := ioutil.ReadAll(gzreader);
if(e2 != nil){
fmt.Println(e2);
}
result := string(output);
Ответ №2:
… У меня есть строка, которая содержит сжатую строку gzip
nbody := "eNorTk0uSi0BAAjRAoc="
Это не «сжатая строка gzip». Это похоже на некоторые данные в кодировке base64, которые необходимо сначала декодировать. После декодирования это также не gzip, а zlib, который в основном такой же, как gzip (содержимое, сжатое с помощью алгоритма deflate), но с другим заголовком файла. Поэтому попытка декодировать ее с помощью gzip не сработает.
Поэтому следующее возьмет вашу исходную строку, расшифрует ее из base64 и распакует ее с помощью zlib (не gzip):
package main
import (
"bytes"
"compress/zlib"
"encoding/base64"
"fmt"
"io/ioutil"
)
func main() {
b64z := "eNorTk0uSi0BAAjRAoc="
z, _ := base64.StdEncoding.DecodeString(b64z)
r, _ := zlib.NewReader(bytes.NewReader(z))
result, _ := ioutil.ReadAll(r)
fmt.Println(string(result)) // results in "secret"
}
Комментарии:
1. Спасибо за ваш ответ, как вы узнали, что нужно использовать zlib? входные данные фактически сжимаются Celery (инструментом python), где я указываю, что хочу сжатие gzip, но на самом деле ваше решение сработало, поэтому я хочу понять, как вы обнаружили, что это сжатая строка zlib
2. @perrohunter: базовый 64 был очевиден. Итак, я сделал
echo 'eNorTk0uSi0BAAjRAoc=' | base64 -d > f; file f
то, что показалf: zlib compressed data
.
Ответ №3:
Если у вас большие входные данные, вы можете вместо этого использовать потоки и пользовательскую цепочку декодеров.
Преимущество заключается в том, что (за исключением этого примера) ни закодированный ввод, ни декодированный вывод не должны находиться в оперативной памяти.
package main
import (
"bytes"
"compress/zlib"
"encoding/base64"
"fmt"
"io"
"log"
"os"
"strings"
)
const nbody = "eNorTk0uSi0BAAjRAoc="
func main() {
_, err := io.Copy(os.Stdout, decoder(strings.NewReader(nbody)))
if err != nil {
log.Fatalf("Error copying decoded value to stdout: %s",err)
}
}
// This could use any io.Reader as input, for example
// a request body in http requests
func decoder(r io.Reader) io.Reader {
// We simply set up a custom chain of Decoders
d, err := zlib.NewReader(
base64.NewDecoder(base64.StdEncoding, r))
// This should only occur if one of the Decoders can not reset
// its internal buffer. Hence, it validates a panic.
if err != nil {
panic(fmt.Sprintf("Error setting up decoder chain: %s", err))
}
// We return an io.Reader which can be used as any other
return d
}
Комментарии:
1. Спасибо за предложение, я рассмотрю это, но мой ввод поступает из большого двоичного объекта json, который извлекается из redis, я могу впоследствии превратить его в поток, а пока я получил решение от Штеффена Ульриха, которое работает