LOKAL Studentenabteilung Adventskalender Tag 6
Ich bin zufällig aufgewachsen, als ich den Artikel am 11. Tag geschrieben habe, also werde ich den leeren Raum ausfüllen.
Beamter: zlib.net Es ist eine Bibliothek von Komprimierungsalgorithmen, die für Zip usw. verwendet werden, und Deflate wird intern implementiert. Da Binärdaten leicht komprimiert werden können, können sie für die Kommunikation verwendet werden. (Ich habe es noch nie ausprobiert) Sie können ziemlich viel sehen, wenn es um Dateikomprimierung geht.
license Die zlib-Lizenz wird auf zlib angewendet. Es ist eine ziemlich lose Lizenz ähnlich dem MIT. Bitte überprüfen Sie für Details.
Weitere Informationen finden Sie unter hier.
compress(data: bytes, level: int = -1) -> bytes
Komprimiert "Daten" zurück.
level
ist das Kompressionsverhältnis.
Enthält Werte von "-1 bis 9" mit einem Standardwert von "-1" (entspricht "6" zum 5. Dezember 2019).
"0" ist nicht komprimiert und "9" hat das höchste Komprimierungsverhältnis.
Je höher das Komprimierungsverhältnis, desto länger dauert es. In den meisten Fällen können Sie die Standardeinstellung beibehalten.
compress()
import zlib
data = b'test data\x00' #Beliebige Binärdaten
compressed = zlib.compress(data)
print(compressed) # b'x\x9c+I-.QHI,Id\x00\x00\x159\x03{'
decompress(data: bytes, wbits: int = 15, bufsize: int = 16384) -> bytes
Entpacken Sie und geben Sie "Daten" zurück.
Die anderen Argumente sind grundsätzlich in Ordnung.
bufsize
wird nach Bedarf erhöht.
decompress()
import zlib
data = b'test data\x00' #Beliebige Binärdaten
decompressed = zlib.decompress(zlib.compress(data))
print(decompressed) # b'test data\x00'
compressobj(level: int = -1, method: int = 8, wbits: int = 15, memLevel: int = 8, strategy: int = 0, zdict: bytes = ...) -> _Compress
Gibt ein komprimiertes Objekt zum Komprimieren von Daten zurück, die nicht gleichzeitig im Speicher gespeichert werden können.
level
ist dasselbe wie compress ()
.
method
ist ein Komprimierungsalgorithmus und ab dem 5. Dezember 2019 ist der einzige unterstützte Wert DEFLATED = 8
zdict
ist ein vordefiniertes komprimiertes Wörterbuch, eine Folge von Bytes, von denen Sie erwarten, dass sie wiederholt in Ihren Daten erscheinen.
compressobj()
import zlib
import io
data_stream = io.BytesIO(b'test data\x00')
cobj = zlib.compressobj()
compressed = b''
while True:
tmp = data_stream.read(64)
if not tmp:
compressed += cobj.flush()
break
compressed += cobj.compress(tmp)
print(compressed) # b'x\x9c+I-.QHI,Id\x00\x00\x159\x03{'
Das Vergessen des letzten flush ()
kann zu unvollständigen Daten führen.
decompressobj(wbits: int = 15, zdict: bytes = ...) -> _Decompress
Das zdict
muss mit dem in compressobj ()
verwendeten identisch sein.
Ändern Sie auch nicht das an zdict übergebene Objekt zwischen dem Aufruf von "decompressobj ()" und dem ersten Aufruf von "decompress ()".
decompressobj()
import zlib
import io
data_stream = io.BytesIO(zlib.compress(b'test data\x00'))
dobj = zlib.decompressobj()
decompressed = b''
while True:
tmp = data_stream.read(64)
if not tmp:
decompressed += dobj.flush()
break
while True:
if not tmp:
break
decompressed += dobj.decompress(tmp)
tmp = dobj.unconsumed_tail
print(decompressed) # b'test data\x00'
Die Bytes, die nicht in den Puffer passten und vom Aufruf "decompress ()" nicht verarbeitet wurden, gehen in den "unconsumed_tail".
Es wird in der Reihenfolge "Header, Dateiname & Pfad, komprimierte Datei" gespeichert und dieser Block wird für die Anzahl der Dateien wiederholt.
file_header
| 00 | 01 | 02 | 03 | 04 | 05 | 06 | 07 |
|---------------------------------------|
| name_len(uint_32) | file_len(uint_32) |
|---------------------------------------|
Es kann mit python mcp.py TARGET [-o OUTPUT]
verwendet werden.
TARGET
ist der Pfad der Datei oder des Verzeichnisses.
Ich habe es nicht für den tatsächlichen Gebrauch geschrieben. Wenn Sie es verwenden, tun Sie dies bitte auf eigenes Risiko.
Die Dekomprimierung erfolgt im 11. Adventskalender.
mcp.py
import sys
import argparse
import os
import zlib
from ctypes import *
import random
import string
import glob
import io
import shutil
tmp_dir = ''.join(random.choices(
string.ascii_letters + string.digits, k=64))+'_mcptmp'
def main():
p = argparse.ArgumentParser(
description='Compress file and dir', usage='Add target to Command line arguments')
p.add_argument('target', help='Compression target')
p.add_argument('--out', '-o', help='Output file path',
default='compressed.mcp')
if len(sys.argv) < 2:
p.print_help()
target = p.parse_args().target
out = p.parse_args().out
if os.path.isfile(target):
_compress_file(target, out)
elif os.path.isdir(target):
_compress_dir(target, out)
else:
raise Exception('Argument error')
def _compress_file(path: str, out: str):
_create_mtp(os.path.basename(path), path)
size = os.path.getsize(os.path.join(tmp_dir, os.path.basename(path)))
with open(os.path.join(tmp_dir, os.path.basename(path)), 'rb') as t:
with open(out, 'wb') as o:
o.write(_make_file_header(size, os.path.basename(path)))
while True:
tmp = t.read(1024)
if not tmp:
o.flush()
break
o.write(tmp)
def _make_file_header(file_len: int, filename: str) -> bytes:
filename_len = len(filename)
return bytes(FileHeaderStructure(filename_len, file_len)) + filename.encode('UTF-8')
def _compress_dir(path: str, out: str):
files = [p[len(path)-1 + len(os.sep):] for p in glob.glob(
os.path.join(path, '**'), recursive=True) if os.path.isfile(p)]
for f in files:
os.makedirs(os.path.join(tmp_dir, os.path.dirname(f)), exist_ok=True)
_create_mtp(f, os.path.join(path, f))
with open(out, 'wb') as o:
for f in files:
o.write(_make_file_header(
os.path.getsize(os.path.join(tmp_dir, f)), f))
with open(os.path.join(tmp_dir, f), 'rb') as t:
while True:
tmp = t.read(1024)
if not tmp:
break
o.write(tmp)
o.flush()
def _create_mtp(path: str, source: str):
c = zlib.compressobj()
with open(source, mode='rb') as f:
with open(os.path.join(tmp_dir, path), mode='wb') as o:
while True:
t = f.read(1024)
if not t:
o.write(c.flush())
break
ced = c.compress(t)
if ced:
o.write(ced)
def _rem_tmp():
shutil.rmtree(tmp_dir)
class FileHeaderStructure(Structure):
_fields_ = (
('filename_len', c_uint32),
('file_len', c_uint32)
)
if __name__ == "__main__":
main()
_rem_tmp()
Ich kann mir keine Möglichkeit vorstellen, die Größe nach der Komprimierung zu ermitteln. Daher gebe ich die komprimierte Größe in eine Datei aus und erhalte die Größe dieser Datei. Wenn Sie die komprimierte Version im Speicher ablegen, können Sie sie mit len () abrufen, aber dann macht es keinen Sinn, kompressobj () zu verwenden ...
Es fiel mir schwer, die an die Daten in der Datei angehängten Header zu erstellen.
Ich bin nicht gut in Python, also denke ich, dass ich es mit C ++ machen kann.
In Python gibt es keine Struktur, aber es scheint, dass Sie so etwas mit einer Klasse erstellen können, die Structure erbt.
Schreiben Sie die Struktur in _fields_
by von ctypes import *
.
Es scheint struct.pack (Format, Werte ...)
zu geben, aber es scheint, dass es nur ~~ Ganzzahlen unterstützt (normalerweise verwendbar) ~~ Es scheint, dass fast alle wichtigen Typen unterstützen (Dokumentation.
Recommended Posts