J'ai un fichier zip d'une taille de 1,5 Go.
Son contenu est un gros fichier de texte brut ridicule (60 Go) et je n'ai actuellement pas assez d'espace sur mon disque pour tout extraire et je ne veux pas tout extraire, même si je l'avais fait.
Quant à mon cas d'utilisation, il suffirait que je puisse inspecter des parties du contenu.
Par conséquent, je veux décompresser le fichier en tant que flux et accéder à une plage du fichier (comme on peut le faire via head et tail sur un fichier texte normal).
Soit par mémoire (par exemple extraire 100 Ko maximum à partir de 32 Go) ou par lignes (donnez-moi les lignes de texte brut 3700-3900).
Y a-t-il un moyen d'y parvenir?
text-processing
zip
k0pernikus
la source
la source
Réponses:
Notez que
gzip
peut extraire deszip
fichiers (au moins la première entrée dans lezip
fichier). Donc, s'il n'y a qu'un seul fichier énorme dans cette archive, vous pouvez faire:Pour extraire les 20 lignes en commençant par la 3000e par exemple.
Ou:
Pour la même chose avec les octets (en supposant une
head
implémentation qui prend en charge-c
).Pour tout membre arbitraire dans l'archive, de manière Unixy:
Avec la fonction
head
intégréeksh93
(comme quand/opt/ast/bin
est en avance$PATH
), vous pouvez également faire:Notez que dans tous les cas,
gzip
/bsdtar
/unzip
devra toujours décompresser (et supprimer ici) la section entière du fichier qui mène à la partie que vous souhaitez extraire. Cela dépend de la façon dont l'algorithme de compression fonctionne.la source
gzip
peut le manipuler, seront les autres services publics « au courant » z (zcat
,zless
, etc.) aussi le travail?gzip
(généralement vraizless
, pas nécessairementzcat
sur certains systèmes pour lire.Z
uniquement les fichiers), oui.Une solution utilisant unzip -p et dd, par exemple pour extraire 10kb avec 1000 blocs offset:
Remarque: je n'ai pas essayé cela avec des données vraiment énormes ...
la source
unzip -l ARCHIVE
pour répertorier le contenu de l'archive etunzip -p ARCHIVE PATH
extraire le contenu d'un seul objetPATH
vers stdout.dd
sur des canaux avec count ou skip n'est pas fiable car elle fera autant deread()
s jusqu'à 1024 octets. Il n'est donc garanti de fonctionner correctement que siunzip
le tube est écrit en morceaux dont la taille est un multiple de 1024.Si vous contrôlez la création de ce gros fichier zip, pourquoi ne pas envisager d'utiliser une combinaison de
gzip
etzless
?Cela vous permettrait d'utiliser
zless
comme pager et d'afficher le contenu du fichier sans avoir à vous soucier de l'extraction.Si vous ne pouvez pas modifier le format de compression, cela ne fonctionnera évidemment pas. Si c'est le cas, je pense que
zless
c'est plutôt pratique.la source
Pour afficher des lignes spécifiques du fichier, dirigez la sortie vers l'éditeur de flux Unix, sed . Cela peut traiter des flux de données arbitrairement volumineux, vous pouvez donc même les utiliser pour modifier les données. Pour afficher les lignes 3700-3900 comme vous l'avez demandé, exécutez ce qui suit.
la source
sed -n 3700,3900p
continuera à lire jusqu'à la fin du fichier. Il vaut mieux utilisersed '3700,$!d;3900q'
pour éviter cela, ou même généralement plus efficace:tail -n +3700 | head -n 201
Je me demandais s'il était possible de faire quelque chose de plus efficace que la décompression du début du fichier jusqu'au point. Il semble que la réponse soit non. Cependant, sur certains processeurs (Skylake)
zcat | tail
ne fait pas monter le CPU à la vitesse d'horloge complète. Voir ci-dessous. Un décodeur personnalisé pourrait éviter ce problème et enregistrer les appels système d'écriture de tuyau, et peut-être être 10% plus rapide. (Ou ~ 60% plus rapide sur Skylake si vous ne modifiez pas les paramètres de gestion de l'alimentation).Le mieux que vous puissiez faire avec un zlib personnalisé avec
skipbytes
fonction serait d'analyser les symboles dans un bloc de compression pour arriver à la fin sans faire le travail de reconstruction réelle du bloc décompressé. Cela pourrait être significativement plus rapide (probablement au moins 2x) que d'appeler la fonction de décodage régulière de zlib pour écraser le même tampon et avancer dans le fichier. Mais je ne sais pas si quelqu'un a écrit une telle fonction. (Et je pense que cela ne fonctionne réellement que si le fichier a été écrit spécialement pour permettre au décodeur de redémarrer à un certain bloc).J'espérais qu'il y avait un moyen de sauter les blocs Deflate sans les décoder, car ce serait beaucoup plus rapide. L'arbre Huffman est envoyé au début de chaque bloc, vous pouvez donc décoder à partir du début de n'importe quel bloc (je pense). Oh, je pense que l'état du décodeur est plus que l'arbre de Huffman, c'est aussi les 32 ko de données décodées précédents, et ce n'est pas réinitialisé / oublié par-delà les limites des blocs par défaut. Les mêmes octets peuvent continuer à être référencés à plusieurs reprises, ils ne peuvent donc apparaître littéralement qu'une seule fois dans un fichier compressé géant. (Par exemple, dans un fichier journal, le nom d'hôte reste probablement "chaud" dans le dictionnaire de compression tout le temps, et chaque instance de celui-ci fait référence au précédent, pas au premier).
Le
zlib
manuel indique que vous devez utiliserZ_FULL_FLUSH
lors de l'appeldeflate
si vous voulez que le flux compressé soit recherché à ce point. Il "réinitialise l'état de compression", donc je pense que sans cela, les références en arrière peuvent aller dans le (s) bloc (s) précédent (s). Donc, à moins que votre fichier zip n'ait été écrit avec des blocs de vidage occasionnels (comme chaque 1G ou quelque chose aurait un impact négligeable sur la compression), je pense que vous auriez à faire plus de travail de décodage jusqu'au point que vous vouliez qu'au départ. en pensant. Je suppose que vous ne pouvez probablement pas commencer au début d'un bloc.Le reste de ceci a été écrit alors que je pensais qu'il serait possible de trouver juste le début du bloc contenant le premier octet que vous voulez, et de décoder à partir de là.
Mais malheureusement, le début d'un bloc Deflate n'indique pas sa durée , pour les blocs compressés. Les données incompressibles peuvent être codées avec un type de bloc non compressé qui a une taille de 16 bits en octets à l'avant, mais pas les blocs compressés: la RFC 1951 décrit le format de manière assez lisible . Les blocs avec codage Huffman dynamique ont l'arborescence à l'avant du bloc (donc le décompresseur n'a pas à chercher dans le flux), donc le compresseur doit avoir gardé le bloc entier (compressé) en mémoire avant de l'écrire.
La distance de référence arrière maximale n'est que de 32 Ko, de sorte que le compresseur n'a pas besoin de conserver beaucoup de données non compressées en mémoire, mais cela ne limite pas la taille du bloc. Les blocs peuvent avoir plusieurs mégaoctets. (Ceci est suffisamment grand pour que le disque en vaille la peine, même sur un lecteur magnétique, par rapport à la lecture séquentielle en mémoire et simplement à l'omission de données dans la RAM, s'il était possible de trouver la fin du bloc actuel sans l'analyse).
zlib crée des blocs le plus longtemps possible: selon Marc Adler , zlib ne démarre un nouveau bloc que lorsque le tampon de symboles se remplit, ce qui avec le paramètre par défaut est 16 383 symboles (littéraux ou correspondances)
J'ai compressé la sortie de
seq
(ce qui est extrêmement redondant et donc probablement pas un excellent test), maispv < /tmp/seq1G.gz | gzip -d | tail -c $((1024*1024*1000)) | wc -c
cela ne fonctionne qu'à ~ 62 Mio / s de données compressées sur un Skylake i7-6700k à 3,9 GHz, avec DDR4-2666 RAM. Cela représente 246 Mo / s de données décompressées, ce qui représente un changement important par rapport à unememcpy
vitesse de ~ 12 Gio / s pour des tailles de bloc trop grandes pour tenir dans le cache.(Avec
energy_performance_preference
la valeur par défautbalance_power
au lieu debalance_performance
, le gouverneur de processeur interne de Skylake décide de ne fonctionner qu'à 2,7 GHz, ~ 43 Mio / s de données compressées. J'utilisesudo sh -c 'for i in /sys/devices/system/cpu/cpufreq/policy[0-9]*/energy_performance_preference;do echo balance_performance > "$i";done'
pour le modifier. Probablement, ces appels système fréquents ne ressemblent pas à de vrais CPU-liés travailler à l'unité de gestion de l'énergie.)TL: DR:
zcat | tail -c
est lié au processeur même sur un processeur rapide, sauf si vous avez des disques très lents. gzip a utilisé 100% du processeur sur lequel il fonctionnait (et a exécuté 1,81 instructions par horloge, selonperf
), et atail
utilisé 0,162 du processeur sur lequel il fonctionnait (0,58 IPC). Le système était par ailleurs essentiellement inactif.J'utilise Linux 4.14.11-1-ARCH, qui a KPTI activé par défaut pour contourner Meltdown, donc tous ces
write
appels systèmegzip
sont plus chers qu'avant : /Avoir la recherche intégrée à
unzip
ouzcat
(mais toujours en utilisant lazlib
fonction de décodage régulière ) permettrait d'économiser toutes ces écritures de pipe et de faire fonctionner les processeurs Skylake à pleine vitesse d'horloge. (Ce downclocking pour certains types de charge est unique à Intel Skylake et versions ultérieures, qui déchargent la prise de décision de fréquence du processeur à partir du système d'exploitation, car ils ont plus de données sur ce que fait le processeur et peuvent augmenter / diminuer plus rapidement. normalement bon, mais ici, Skylake ne monte pas à pleine vitesse avec un réglage de gouverneur plus conservateur).Aucun appel système, simplement réécrire un tampon qui tient dans le cache L2 jusqu'à ce que vous atteigniez la position d'octet de départ que vous souhaitez, ferait probablement au moins une différence de quelques%. Peut-être même 10%, mais je fais juste des chiffres ici. Je n'ai pas profilé
zlib
en détail pour voir la taille d'une empreinte de cache, et combien le vidage TLB (et donc le vidage uop-cache) sur chaque appel système fait mal avec KPTI activé.Il existe quelques projets logiciels qui ajoutent un index de recherche au format de fichier gzip . Cela ne vous aide pas si vous ne parvenez pas à faire en sorte que quelqu'un génère des fichiers compressés recherchés pour vous, mais d'autres futurs lecteurs pourraient en bénéficier.
Vraisemblablement, aucun de ces projets n'a de fonction de décodage qui sait ignorer un flux Deflate sans index, car ils ne sont conçus pour fonctionner que lorsqu'un index est disponible.
la source
Vous pouvez ouvrir le fichier zip dans une session python, en utilisant
zf = zipfile.ZipFile(filename, 'r', allowZip64=True)
et une fois ouvert, vous pouvez ouvrir, pour lire, n'importe quel fichier à l'intérieur de l'archive zip et lire des lignes, etc., comme s'il s'agissait d'un fichier normal.la source