Comment gzip compresser une chaîne en Python?

86

Comment gzip compresser une chaîne en Python?

gzip.GzipFile existe, mais c'est pour les objets fichier - qu'en est-il des chaînes simples?

Bdfy
la source
1
@KevinDTimm, ce document ne mentionne que StringIOmais n'explique pas vraiment comment le faire. Donc poser cette question ici est tout à fait valable, à mon humble avis. Quelques essais supplémentaires avant de les poser et de nous en parler auraient été bien, cependant.
Alfe
@Alfe - la question a été fermée il y a 4 ans pour à peu près la même raison que mon commentaire - l'OP n'a fait aucun effort pour rechercher en premier.
KevinDTimm
4
Comment est-ce hors sujet?
2
Cette question est le premier succès dans Google maintenant gzip string in pythonet est très raisonnable IMO. Il devrait être rouvert.
Garrett
2
Comme ci-dessus, cette question est le premier résultat d'une recherche Google, et l'une des réponses est correcte - il semble vraiment qu'elle ne devrait pas être fermée.
darkdan21 le

Réponses:

156

Si vous souhaitez produire une gzipchaîne binaire compatible complète , avec l'en-tête, etc., vous pouvez utiliser gzip.GzipFileavec 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
la source
2
Le contraire de ceci est: `def gunzip_text (text): infile = StringIO.StringIO () infile.write (text) with gzip.GzipFile (fileobj = infile, mode =" r ") as f: f.rewind () f .read () return out.getvalue ()
fastmultiplication
3
@fastmultiplication: ou plus court:f = gzip.GzipFile(StringIO.StringIO(text)); result = f.read(); f.close(); return result
Alfe
2
Malheureusement, la question est proche, je ne peux donc pas apporter de nouvelle réponse, mais voici comment faire cela dans Python 3.
Garrett
Probablement sans rapport, la compression en mémoire est-elle d'abord plus rapide (en utilisant un disque local)?
user3226167
1
En 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

Le moyen le plus simple est l' zlib encodage :

compressed_value = s.encode("zlib")

Ensuite, vous le décompressez avec:

plain_string_again = compressed_value.decode("zlib")
Sven Marnach
la source
1
@Daniel: Oui, sc'est un objet Python 2.x de type str.
Sven Marnach
2
Voir Encodages standard pour savoir où il a obtenu cela (faites défiler jusqu'à "codecs" ). Aussi disponible: s.encode('rot13'),s.encode( 'base64' )
bobobobo
8
Notez que cette méthode est incompatible avec l'utilitaire de ligne de commande gzip dans la mesure où gzip inclut un en-tête et une somme de contrôle, alors que ce mécanisme compresse simplement le contenu.
tylerl
Je sais que c'est vieux mais votre ligne de code pour la décompression devrait être: plain_string_again = compressed_value.decode("zlib")
minillinim
6
@BenjaminToueg: Python 3 est plus strict sur la distinction entre les chaînes Unicode (type stren Python 3) et les chaînes d'octets (type bytes). strles objets ont une encode()méthode qui renvoie un bytesobjet et les bytesobjets ont une decode()méthode qui renvoie un str. Le zlibcodec est spécial en ce qu'il convertit de bytesen bytes, donc il ne rentre pas dans cette structure. Vous pouvez utiliser codecs.encode(b, "zlib")et codecs.decode(b, "slib")pour un bytesobjet à la bplace.
Sven Marnach
22

Version Python3 de la réponse de Sven Marnach en 2011:

import gzip
exampleString = 'abcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijmortenpunnerudengelstadrocksklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuv123'
compressed_value = gzip.compress(bytes(exampleString,'utf-8'))
plain_string_again  = gzip.decompress(compressed_value)
Punnerud
la source
2
En Python 3 zlibest toujours utilisé, gziputilise réellement zlib, voir: docs.python.org/3/library/zlib.html et docs.python.org/3/library/gzip.html#module-gzip
gitaarik
Ma réponse originale utilisait zlib. Changé en gzip car c'était la question d'origine. Vous pouvez facilement remplacer de gzip à zlib (rechercher et remplacer) dans mon exemple, et cela fonctionnera.
Punnerud
2

Pour ceux qui souhaitent compresser un dataframe Pandas au format JSON:

Testé avec Python 3.6 et 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
la source
-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
la source
4
Je suppose que la question portait sur la compression d'une chaîne en mémoire sans avoir à l'écrire sur le disque dans le processus. Sinon, votre réponse est tout à fait correcte.
Alfe