Calendrier de l'Avent du Département étudiant LOCAL Jour 6
J'ai grandi en écrivant l'article le 11ème jour, alors je vais remplir l'espace vide.
Officiel: zlib.net Il s'agit d'une bibliothèque d'algorithmes de compression utilisés pour Zip, etc., et Deflate est implémenté en interne. Puisque les données binaires peuvent être facilement compressées, elles peuvent être utilisées pour la communication. (Je n'ai jamais essayé) Vous pouvez voir beaucoup de choses en matière de compression de fichiers.
license La licence zlib est appliquée à zlib. C'est une licence assez lâche similaire au MIT. Veuillez vérifier les détails.
Pour plus d'informations, veuillez consulter ici
compress(data: bytes, level: int = -1) -> bytes
Compresse en arrière data
.
«level» est le taux de compression.
Contient des valeurs de «-1 à 9», avec une valeur par défaut de «-1» (équivalente à «6» au 5 décembre 2019).
«0» est non compressé et «9» a le taux de compression le plus élevé.
Plus le taux de compression est élevé, plus cela prendra du temps, donc dans la plupart des cas, vous pouvez laisser la valeur par défaut.
compress()
import zlib
data = b'test data\x00' #Données binaires arbitraires
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
Décompressez et renvoyez «data».
Les autres arguments sont fondamentalement bons par défaut.
bufsize
est incrémenté selon les besoins.
decompress()
import zlib
data = b'test data\x00' #Données binaires arbitraires
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
Renvoie un objet compressé pour compresser des données qui ne peuvent pas être stockées en mémoire en une seule fois.
«level» est le même que «compress ()».
method
est un algorithme de compression et depuis le 5 décembre 2019, la seule valeur prise en charge est DEFLATED = 8
zdict
est un dictionnaire compressé prédéfini, une séquence d'octets que vous prévoyez d'apparaître à plusieurs reprises dans vos données.
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{'
Oublier le dernier flush ()
peut entraîner des données incomplètes.
decompressobj(wbits: int = 15, zdict: bytes = ...) -> _Decompress
Le zdict
doit être le même que celui utilisé dans compressobj ()
.
Aussi, ne changez pas l'objet passé à zdict entre l'appel à decompressobj ()
et le premier appel à 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'
Les octets qui ne rentrent pas dans le tampon et qui n'ont pas été traités par l'appel decompress ()
vont dans ʻunconsumed_tail`.
Il est enregistré dans l'ordre «en-tête, nom de fichier et chemin, fichier_comprimé», et ce bloc est répété pour le nombre de fichiers.
file_header
| 00 | 01 | 02 | 03 | 04 | 05 | 06 | 07 |
|---------------------------------------|
| name_len(uint_32) | file_len(uint_32) |
|---------------------------------------|
Il peut être utilisé avec python mcp.py TARGET [-o OUTPUT]
.
«TARGET» est le chemin du fichier ou du répertoire.
Je ne l'ai pas écrit pour une utilisation réelle, donc si vous l'utilisez, veuillez le faire à vos propres risques.
La décompression se fera le 11e calendrier de l'Avent.
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()
Je ne peux pas penser à un moyen d'obtenir la taille après la compression, donc je sortie le fichier compressé dans un fichier et obtiens la taille de ce fichier.
Si vous mettez la version compressée en mémoire, vous pouvez l'obtenir avec len ()
, mais alors il ne sert à rien d'utiliser compressobj ()
...
J'ai eu du mal à créer les en-têtes attachés aux données du fichier.
Je ne suis pas bon en Python, donc je pense que je peux le faire avec C ++.
Il n'y a pas de structure en Python, mais il semble que vous puissiez créer quelque chose comme ça en utilisant une classe qui hérite de Structure.
Écrivez la structure dans _fields_
par à partir de ctypes import *
.
Il semble y avoir struct.pack (format, valeurs ...)
, mais il semble qu'il ne supporte que les ~~ entiers (généralement utilisables) ~~ Il semble que presque tous les types principaux prennent en charge (Documentation.
Recommended Posts