ฉันจะบีบอัด gzip สตริงใน Python ได้อย่างไร


87

ฉันจะบีบอัด gzip สตริงใน Python ได้อย่างไร

gzip.GzipFile มีอยู่ แต่สำหรับอ็อบเจ็กต์ไฟล์แล้วสตริงธรรมดาล่ะ


1
@KevinDTimm ที่ docu กล่าวถึงเท่านั้นStringIOแต่ไม่ได้อธิบายถึงวิธีการทำจริงๆ ดังนั้นการถามคำถามที่นี่จึงใช้ได้อย่างสมบูรณ์ IMHO แม้ว่าการทดลองเพิ่มเติมบางอย่างก่อนที่จะถามและบอกเราเกี่ยวกับสิ่งเหล่านี้น่าจะดี
Alfe

@Alfe - คำถามถูกปิดเมื่อ 4 ปีที่แล้วด้วยเหตุผลเดียวกับความคิดเห็นของฉัน - OP ไม่ได้พยายามค้นหาก่อน
KevinDTimm

4
นอกประเด็นนี้อย่างไร

2
คำถามนี้เป็นคำถามยอดนิยมใน Google ตอนนี้สำหรับgzip string in pythonIMO และสมเหตุสมผลมาก มันควรจะเปิดใหม่
Garrett

2
ข้างต้นคำถามนี้เป็นผลการค้นหาอันดับต้น ๆ ในการค้นหาของ Google และหนึ่งในคำตอบนั้นถูกต้อง - ดูเหมือนว่าไม่ควรปิด
darkdan21

คำตอบ:


156

หากคุณต้องการสร้างgzipสตริงไบนารีที่เข้ากันได้โดยสมบูรณ์โดยมีส่วนหัวเป็นต้นคุณสามารถใช้gzip.GzipFileร่วมกับ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'

2
สิ่งที่ตรงกันข้ามคือ: `def gunzip_text (text): infile = StringIO.StringIO () infile.write (text) กับ gzip.GzipFile (fileobj = infile, mode =" r ") เป็น f: f.rewind () f .read () return out.getvalue ()
fastmultiplication

3
@fastmultiplication: หรือสั้นกว่า:f = gzip.GzipFile(StringIO.StringIO(text)); result = f.read(); f.close(); return result
Alfe

2
น่าเสียดายที่คำถามใกล้เข้ามาแล้วฉันจึงไม่สามารถหาคำตอบใหม่ได้ แต่นี่คือวิธีดำเนินการใน Python 3
Garrett

อาจไม่เกี่ยวข้องกำลังบีบอัดในหน่วยความจำเร็วขึ้นก่อน (โดยใช้ดิสก์ภายใน) หรือไม่?
user3226167

1
ใน 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

วิธีที่ง่ายที่สุดคือการzlib เข้ารหัส :

compressed_value = s.encode("zlib")

จากนั้นคุณขยายขนาดด้วย:

plain_string_again = compressed_value.decode("zlib")

1
@ Daniel: ใช่sเป็นวัตถุ 2.x strหลามประเภท
Sven Marnach

2
ดูการเข้ารหัสมาตรฐานที่เขาได้รับ (เลื่อนลงไปที่"ตัวแปลงสัญญาณ" ) นอกจากนี้ยังมี: s.encode('rot13'),s.encode( 'base64' )
bobobobo

8
โปรดทราบว่าวิธีนี้ใช้ไม่ได้กับยูทิลิตี้บรรทัดคำสั่ง gzip ใน gzip นั้นมีส่วนหัวและการตรวจสอบในขณะที่กลไกนี้จะบีบอัดเนื้อหาเท่านั้น
tylerl

ฉันรู้ว่านี้เป็นรุ่นเก่า แต่คุณบรรทัดของรหัสสำหรับคลายควรจะ: plain_string_again = compressed_value.decode("zlib")
minillinim

6
@BenjaminToueg: Python 3 เข้มงวดกว่าเกี่ยวกับความแตกต่างระหว่างสตริง Unicode (พิมพ์strใน Python 3) และสตริงไบต์ (ประเภทbytes) strวัตถุมีencode()วิธีที่ส่งคืนbytesวัตถุและbytesวัตถุมีdecode()วิธีการที่ส่งกลับstr. zlibตัวแปลงสัญญาณเป็นพิเศษในการที่จะแปลงจากbytesไปbytesเพื่อให้มันไม่พอดีในโครงสร้างนี้ คุณสามารถใช้codecs.encode(b, "zlib")และcodecs.decode(b, "slib")สำหรับbytesวัตถุbแทนได้
Sven Marnach

22

คำตอบของปี 2011 ของ Sven Marnach เวอร์ชัน Python3:

import gzip
exampleString = 'abcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijmortenpunnerudengelstadrocksklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvabcdefghijklmnopqrstuv123'
compressed_value = gzip.compress(bytes(exampleString,'utf-8'))
plain_string_again  = gzip.decompress(compressed_value)

2
ใน Python 3 zlibยังคงมีการใช้งานgzipจริงzlibโปรดดู: docs.python.org/3/library/zlib.htmlและdocs.python.org/3/library/gzip.html#module-gzip
gitaarik

คำตอบเดิมของฉันคือใช้ zlib เปลี่ยนเป็น gzip เพราะนั่นคือคำถามเดิม คุณสามารถแทนที่จาก gzip เป็น zlib (ค้นหาและแทนที่) ในตัวอย่างของฉันได้อย่างง่ายดายและจะใช้งานได้
Punnerud

2

สำหรับผู้ที่ต้องการบีบอัดดาต้าเฟรมของ Pandas ในรูปแบบ JSON:

ทดสอบกับ Python 3.6 และ 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())

-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()

4
ฉันเดาว่าคำถามเกี่ยวกับการบีบอัดสตริงในหน่วยความจำโดยไม่ต้องเขียนลงดิสก์ในกระบวนการ มิฉะนั้นคำตอบของคุณจะถูกต้องทั้งหมด
Alfe
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.