Jak skompresować gzip ciąg znaków w Pythonie?

87

Jak skompresować gzip ciąg znaków w Pythonie?

gzip.GzipFile istnieje, ale dotyczy to obiektów plików - a co ze zwykłymi łańcuchami?

Bdfy
źródło
1
@KevinDTimm, ten dokument tylko wspomina, StringIOale tak naprawdę nie wyjaśnia, jak to zrobić. Więc zadawanie tego pytania tutaj jest całkowicie uzasadnione, IMHO. Jednak kilka dodatkowych prób, zanim zapytasz nas i opowiesz o nich, byłoby miłe.
Alfe
@Alfe - pytanie zostało zamknięte 4 lata temu z tego samego powodu, co mój komentarz - OP nie podjął żadnego wysiłku, aby najpierw wyszukać.
KevinDTimm
4
Jak to jest poza tematem?
2
To pytanie jest obecnie najpopularniejszym hitem w Google gzip string in pythoni jest bardzo rozsądnym IMO. Powinien zostać ponownie otwarty.
Garrett
2
Jak wyżej, to pytanie jest najlepszym wynikiem w wyszukiwarce Google, a jedna z odpowiedzi jest poprawna - wydaje się, że nie powinno być zamykane.
darkdan21

Odpowiedzi:

156

Jeśli chcesz stworzyć kompletny gzipciąg binarny zgodny z nagłówkiem itp., Możesz użyć gzip.GzipFilerazem z 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
źródło
2
Przeciwieństwem tego jest: `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: lub krócej:f = gzip.GzipFile(StringIO.StringIO(text)); result = f.read(); f.close(); return result
Alfe
2
Niestety, pytanie było blisko, więc nie mogę udzielić nowej odpowiedzi, ale oto jak to zrobić w Pythonie 3.
Garrett
Prawdopodobnie nie ma związku, czy kompresja w pamięci jest najpierw szybsza (przy użyciu dysku lokalnego)?
user3226167
1
W Pythonie 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

Najłatwiejszym sposobem jest zlib kodowanie :

compressed_value = s.encode("zlib")

Następnie dekompresujesz go za pomocą:

plain_string_again = compressed_value.decode("zlib")
Sven Marnach
źródło
1
@Daniel: Tak, sto Python 2.x obiekt typu str.
Sven Marnach
2
Zobacz Standardowe kodowanie, aby dowiedzieć się, skąd to wziął (przewiń w dół do „kodeków” ). Dostępne również: s.encode('rot13'),s.encode( 'base64' )
bobobobo
8
Zauważ, że ta metoda jest niekompatybilna z narzędziem wiersza poleceń gzip, ponieważ gzip zawiera nagłówek i sumę kontrolną, podczas gdy ten mechanizm po prostu kompresuje zawartość.
tylerl
Wiem, że to jest stare, ale wiersz kodu do dekompresji powinien wyglądać następująco: plain_string_again = compressed_value.decode("zlib")
minillinim.
6
@BenjaminToueg: Python 3 jest bardziej rygorystyczny w kwestii rozróżnienia między ciągami znaków Unicode (typ strw Pythonie 3) a ciągami bajtów (typ bytes). strobiekty mają encode()metodę, która zwraca bytesobiekt, a bytesobiekty mają decode()metodę, która zwraca str. zlibKodek jest wyjątkowy w tym, że przetwarza od bytescelu bytes, więc nie pasuje do tej struktury. Zamiast tego możesz użyć codecs.encode(b, "zlib")i codecs.decode(b, "slib")dla bytesobiektu b.
Sven Marnach
22

Wersja Python3 odpowiedzi Svena Marnacha z 2011 roku:

import gzip
exampleString = 'abcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijmortenpunnerudengelstadrocksklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuv123'
compressed_value = gzip.compress(bytes(exampleString,'utf-8'))
plain_string_again  = gzip.decompress(compressed_value)
Punnerud
źródło
2
W Pythonie 3 zlibjest nadal używany, w gziprzeczywistości używa zlib, patrz: docs.python.org/3/library/zlib.html i docs.python.org/3/library/gzip.html#module-gzip
gitaarik
Moja pierwotna odpowiedź dotyczyła zlib. Zmieniono na gzip, ponieważ to było oryginalne pytanie. W moim przykładzie możesz łatwo zamienić z gzip na zlib (wyszukaj i zamień) i zadziała.
Punnerud,
2

Dla tych, którzy chcą skompresować ramkę danych Pandas w formacie JSON:

Testowane z Pythonem 3.6 i 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
źródło
-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
źródło
4
Wydaje mi się, że chodziło o skompresowanie ciągu znaków w pamięci bez konieczności zapisywania go na dysku. W przeciwnym razie twoja odpowiedź jest całkowicie poprawna.
Alfe