Versuchen Sie, eine komprimierte Datei mit Python und zlib zu erstellen

Einführung

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.

Was ist zlib?

Überblick

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.

Versuchen Sie es mit

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".

Erstellen Sie eine komprimierte Datei

Konstruktion

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

Implementierung

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

Versuchen Sie, eine komprimierte Datei mit Python und zlib zu erstellen
Versuchen Sie, das DeepZoom-Dateiformat .DZI in Python zu erstellen
Erstellen einer einfachen Power-Datei mit Python
Verarbeiten Sie das Ausführungsergebnis von Splunk mit Python und speichern Sie es in einer Datei
Erstellen eines Markierungsblatts mit Python OpenCV (Tipps zum guten Lesen)
Erstellen Sie eine GIF-Datei mit Pillow in Python
Erstellen Sie eine Webmap mit Python und GDAL
Ich habe versucht, eine CSV-Datei mit Python zu lesen
Führen Sie Python-Dateien mit Django aus HTML aus
Versuchen Sie es mit Tensorflow. ① Erstellen Sie eine Python-Umgebung und führen Sie Tensorflow ein
Erstellen Sie eine MIDI-Datei in Python mit pretty_midi
Versuchen Sie, die ChatWork-API und die Qiita-API in Python zu verwenden
Versuchen Sie es mit Tweepy [Python2.7]
Versuchen Sie, mithilfe der Python-Anforderungsbibliothek eine Webseite und eine JSON-Datei abzurufen
Erstellen eines Temperaturregelungssystems mit Himbeerkuchen und ESP32 (3) Empfangen einer Python-Datei
Python: Erstellen einer virtuellen Umgebung (venv), Starten und Stoppen
(Python) Versuchen Sie, eine Webanwendung mit Django zu entwickeln
Erstellen Sie ein Diagramm mit der Plot-Schaltfläche und dem Schieberegler
Implementieren eines Generators mit Python> Link> Yield und next ()> Yield
[Python] Starten Sie eine Batchdatei aus Python und übergeben Sie Variablen.
[Python] Versuchen Sie, Tkinters Leinwand zu verwenden
Versuchen Sie es mit Kubernetes Client -Python-
Dateien lesen und schreiben
Dateien schreiben und lesen
Versuchen Sie es mit pytest-Overview und Samples-
Versuchen Sie es mit GUI, PyQt in Python
Versuchen Sie, eine Excel-Datei mit Python (Pandas / XlsxWriter) zu betreiben
Erstellen einer Python-Umgebung auf einem Mac bis zur Verwendung von Jupyter Lab
Versuchen Sie, eine Excel-Datei mit Python (Pandas / XlsxWriter) zu betreiben
[Python] Kapitel 01-03 Über Python (Schreiben und Ausführen eines Programms mit PyCharm)
Probieren Sie die ähnliche Suche von Image Search mit Python SDK [Search] aus.
Ein Hinweis beim Erstellen eines gerichteten Diagramms mit Graphviz in Python
Versuchen Sie, ein Unterfenster mit PyQt5 und Python zu öffnen
Versuchen Sie, ein neuronales Netzwerk in Python aufzubauen, ohne eine Bibliothek zu verwenden
Versuchen Sie, eine in Python geschriebene Funktion mit Fn Project auszuführen
Nehmen Sie Zeitraffer von einer PC-Kamera mit Python, OpenCV auf
Versuchen Sie einfach, einen Webhook mit ngrok und Python zu erhalten
Ich habe Chatbot mit LINE Messaging API und Python erstellt
Erstellen einer Webanwendung mit Flask ②
Erstellen eines WAV-Dateiteilungsprogramms
Ich habe einen Line-Bot mit Python gemacht!
Erstellen Sie mit tkinter eine Python-GUI
Python: Einführung in Flask: Erstellen einer Nummernidentifizierungs-App mit MNIST
Authentifizierung mit Tweepy-User-Authentifizierung und Anwendungsauthentifizierung (Python)
Erstellen Sie mit Python und Redis eine Rangliste für Spiele in der Alibaba-Cloud
Zeichnen einer Silbersteinkurve mit Python
Versuchen Sie es mit virtualenv, mit dem eine virtuelle Umgebung von Python erstellt werden kann
Versuchen Sie es mit der Pleasant-API (Python / FastAPI).
Versuchen Sie es mit LevelDB mit Python (plyvel)
Erstellen einer einfachen Tabelle mit Stettytable
Erstellen Sie eine Binärdatei in Python
Ein bisschen mehr über Referenzen ~ Verwenden von Python und Java als Beispiele ~
Erstellen Sie einen einfachen geplanten Stapel mit Dockers Python Image und parse-crontab
Lesen und Schreiben von Python CSV-Dateien
Erstellen und testen Sie mit Docker in wenigen Minuten eine OpenCV- und Python-Umgebung
[Python] So kratzen Sie eine lokale HTML-Datei und geben sie mit Beautiful Soup als CSV aus
Hinzufügen von Excel-Dateispalten und Löschen von Zeilen mithilfe von Python Openpyxl
Clustering und Visualisierung mit Python und CytoScape
Ich habe Node.js und Python beim Erstellen eines Miniaturbilds mit AWS Lambda verglichen