Como faço para compactar gzip uma string em Python?

86

Como faço para compactar gzip uma string em Python?

gzip.GzipFile existe, mas isso é para objetos de arquivo - e quanto a strings simples?

Bdfy
fonte
1
@KevinDTimm, esse documento apenas menciona, StringIOmas não explica realmente como fazê-lo. Então, fazer essa pergunta aqui é totalmente válido, IMHO. No entanto, mais algumas tentativas antes de nos perguntar e nos contar sobre eles teriam sido legais.
Alfe
@Alfe - a pergunta foi encerrada há 4 anos pelo mesmo motivo do meu comentário - o OP não fez nenhum esforço para pesquisar primeiro.
KevinDTimm
4
Como isso está fora do assunto?
2
Esta questão é o maior hit no google agora gzip string in pythone é muito razoável IMO. Deve ser reaberto.
Garrett
2
Como acima, esta pergunta é o principal resultado de uma pesquisa no Google e uma das respostas está correta - realmente parece que ela não deveria ser fechada.
darkdan21

Respostas:

156

Se você quiser produzir uma gzipstring binária totalmente compatível, com o cabeçalho, etc., você pode usar gzip.GzipFilejunto com StringIO:

try:
    from StringIO import StringIO  # Python 2.7
except ImportError:
    from io import StringIO  # Python 3.x
import gzip
out = StringIO()
with gzip.GzipFile(fileobj=out, mode="w") as f:
  f.write("This is mike number one, isn't this a lot of fun?")
out.getvalue()

# returns '\x1f\x8b\x08\x00\xbd\xbe\xe8N\x02\xff\x0b\xc9\xc8,V\x00\xa2\xdc\xcc\xecT\x85\xbc\xd2\xdc\xa4\xd4"\x85\xfc\xbcT\x1d\xa0X\x9ez\x89B\tH:Q!\'\xbfD!?M!\xad4\xcf\x1e\x00w\xd4\xea\xf41\x00\x00\x00'
NPE
fonte
2
O oposto disso é: `def gunzip_text (text): infile = StringIO.StringIO () infile.write (text) com gzip.GzipFile (fileobj = infile, mode =" r ") as f: f.rewind () f .read () return out.getvalue ()
fastmultiplication
3
@fastmultiplication: or short:f = gzip.GzipFile(StringIO.StringIO(text)); result = f.read(); f.close(); return result
Alfe
2
Infelizmente, a pergunta está fechada, então não posso dar uma nova resposta, mas aqui está como fazer isso no Python 3.
Garrett
Provavelmente não relacionado, a compactação na memória é mais rápida (usando o disco local)?
user3226167
1
Em Python 3:import zlib; my_string = "hello world"; my_bytes = zlib.compress(my_string.encode('utf-8')); my_hex = my_bytes.hex(); my_bytes2 = bytes.fromhex(my_hex); my_string2 = zlib.decompress(my_bytes); assert my_string == my_string2;
ostrokach
64

A maneira mais fácil é a zlib codificação :

compressed_value = s.encode("zlib")

Então você descompacta com:

plain_string_again = compressed_value.decode("zlib")
Sven Marnach
fonte
1
@ Daniel: Sim, sé um objeto 2.x do Python do tipo str.
Sven Marnach
2
Veja Codificações padrão para saber onde ele conseguiu isso (role para baixo até "codecs" ). Também disponível: s.encode('rot13'),s.encode( 'base64' )
bobobobo
8
Observe que esse método é incompatível com o utilitário de linha de comando gzip, pois o gzip inclui um cabeçalho e uma soma de verificação, enquanto esse mecanismo simplesmente compacta o conteúdo.
tylerl
Eu sei que isso é antigo, mas sua linha de código para descompactar deve ser: plain_string_again = compressed_value.decode("zlib")
minillinim
6
@BenjaminToueg: Python 3 é mais estrito sobre a distinção entre strings Unicode (tipo strem Python 3) e strings de byte (tipo bytes). stros objetos têm um encode()método que retorna um bytesobjeto e os bytesobjetos têm um decode()método que retorna a str. O zlibcodec é especial porque pode ser convertido de bytespara bytes, portanto, não se encaixa nessa estrutura. Você pode usar codecs.encode(b, "zlib")e codecs.decode(b, "slib")para um bytesobjeto b.
Sven Marnach
22

Versão Python3 da resposta de Sven Marnach de 2011:

import gzip
exampleString = 'abcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijmortenpunnerudengelstadrocksklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuv123'
compressed_value = gzip.compress(bytes(exampleString,'utf-8'))
plain_string_again  = gzip.decompress(compressed_value)
Punnerud
fonte
2
Em Python 3 zlibainda é usado, gziprealmente usa zlib, consulte: docs.python.org/3/library/zlib.html e docs.python.org/3/library/gzip.html#module-gzip
gitaarik
Minha resposta original era usar zlib. Alterado para gzip porque essa era a pergunta original. Você pode facilmente substituir de gzip para zlib (pesquisar e substituir) no meu exemplo, e funcionará.
Punnerud de
2

Para quem deseja compactar um dataframe Pandas no formato JSON:

Testado com Python 3.6 e Pandas 0.23

import sys
import zlib, lzma, bz2
import math

def convert_size(size_bytes):
    if size_bytes == 0:
        return "0B"
    size_name = ("B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB")
    i = int(math.floor(math.log(size_bytes, 1024)))
    p = math.pow(1024, i)
    s = round(size_bytes / p, 2)
    return "%s %s" % (s, size_name[i])

dataframe = pd.read_csv('...') # your CSV file
dataframe_json = dataframe.to_json(orient='split')
data = dataframe_json.encode()
compressed_data = bz2.compress(data)
decompressed_data = bz2.decompress(compressed_data).decode()
dataframe_aux = pd.read_json(decompressed_data, orient='split')

#Original data size:  10982455 10.47 MB
#Encoded data size:  10982439 10.47 MB
#Compressed data size:  1276457 1.22 MB (lzma, slow), 2087131 1.99 MB (zlib, fast), 1410908 1.35 MB (bz2, fast)
#Decompressed data size:  10982455 10.47 MB
print('Original data size: ', sys.getsizeof(dataframe_json), convert_size(sys.getsizeof(dataframe_json)))
print('Encoded data size: ', sys.getsizeof(data), convert_size(sys.getsizeof(data)))
print('Compressed data size: ', sys.getsizeof(compressed_data), convert_size(sys.getsizeof(compressed_data)))
print('Decompressed data size: ', sys.getsizeof(decompressed_data), convert_size(sys.getsizeof(decompressed_data)))

print(dataframe.head())
print(dataframe_aux.head())
Andrews Sobral
fonte
-4
s = "a long string of characters"

g = gzip.open('gzipfilename.gz', 'w', 5) # ('filename', 'read/write mode', compression level)
g.write(s)
g.close()
Jon Mitten
fonte
4
Acho que a questão era sobre como compactar uma string na memória sem precisar gravá-la no disco no processo. Caso contrário, sua resposta está totalmente correta.
Alfe