Si un gros fichier zip est téléchargé sur un serveur et que vous n'avez besoin que d'une partie de son contenu, existe-t-il un moyen de l'ouvrir et de choisir ce que vous voulez télécharger ?
Au fait, ce aidé.
Si un gros fichier zip est téléchargé sur un serveur et que vous n'avez besoin que d'une partie de son contenu, existe-t-il un moyen de l'ouvrir et de choisir ce que vous voulez télécharger ?
J'ai écrit un Python script list_remote_zip.py
qui peut lister les fichiers dans un fichier zip accessible par HTTP :
import urllib2, struct, sys
def open_remote_zip(url, offset=0):
return urllib2.urlopen(urllib2.Request(url, headers={'Range': 'bytes={}-'.format(offset)}))
offset = 0
zipfile = open_remote_zip(sys.argv[1])
header = zipfile.read(30)
while header[:4] == 'PK\x03\x04':
compressed_len, uncompressed_len = struct.unpack('<II', header[18:26])
filename_len, extra_len = struct.unpack('<HH', header[26:30])
header_len = 30 + filename_len + extra_len
total_len = header_len + compressed_len
print('{}\n offset: {}\n length: {}\n header: {}\n payload: {}\n uncompressed length: {}'.format(zipfile.read(filename_len), offset, total_len, header_len, compressed_len, uncompressed_len))
zipfile.close()
offset += total_len
zipfile = open_remote_zip(sys.argv[1], offset)
header = zipfile.read(30)
zipfile.close()
Il n'utilise pas le répertoire central du fichier zip, qui se trouve vers la fin du fichier. Au lieu de cela, il part du début, analyse les en-têtes locaux individuels et passe au-dessus de la charge utile, en espérant atterrir sur un autre en-tête. Il envoie une nouvelle requête chaque fois qu'il a besoin de passer à un décalage. Bien entendu, cela ne fonctionne qu'avec les serveurs qui prennent en charge la fonction Range
En-tête HTTP.
Il suffit de lui transmettre l'URL du fichier zip comme argument de ligne de commande. Un exemple d'utilisation et de sortie devrait ressembler à ceci :
$ python list_remote_zip.py http://dl.xonotic.org/xonotic-0.8.1.zip
Xonotic/Makefile
offset: 0
length: 1074
header: 46
payload: 1028
uncompressed length: 5019
Xonotic/source/darkplaces/
offset: 1074
length: 56
header: 56
payload: 0
uncompressed length: 0
Xonotic/source/darkplaces/bih.h
offset: 1130
length: 1166
header: 61
payload: 1105
uncompressed length: 2508
Xonotic/source/darkplaces/portals.h
offset: 2296
length: 334
header: 65
payload: 269
uncompressed length: 648
...
Pour télécharger un des fichiers, j'ai écrit un fichier encore plus moche get_file_from_remote_zip.sh
bash script autour de lui qui utilise wget
:
info=$(python list_remote_zip.py "$1" | grep -m 1 -A 5 "^$2\$" | tail -n +2)
tmpfile=$(mktemp)
wget --start-pos $(echo "$info" | grep offset | grep -o '[[:digit:]]*') -O - "$1" | head -c $(echo "$info" | grep -m 1 length | grep -o '[[:digit:]]*') >"$tmpfile"
printf '\x1f\x8b' # gzip magic
tail -c +9 <"$tmpfile" | head -c 1 # copy compression method
printf '\0\0\0\0\0\0\x03' # some flags and mtime
tail -c "+$(expr 1 + $(echo "$info" | grep header | grep -o '[[:digit:]]*'))" <"$tmpfile"
tail -c +15 <"$tmpfile" | head -c 4 # The CRCs seem to be compatible.
tail -c +23 <"$tmpfile" | head -c 4
rm "$tmpfile"
Il faut 2 arguments. Le premier est l'URL du fichier zip et le second le fichier à extraire. Le nom du fichier à extraire doit être complet et exactement tel qu'il apparaît dans le résultat de l'opération précédente. list_remote_zip.py
Python script, qu'il utilise pour obtenir des informations sur le fichier. Il utilise ensuite wget
pour le télécharger avec le bon décalage et la bonne longueur. Il enregistre cette "tranche" de zip dans un fichier temporaire, qui est ensuite utilisé pour produire un fichier de type gzip
-qui peut ensuite être acheminé et décompressé avec la commande gzip
. La "tranche" elle-même n'est pas un fichier zip valide car elle n'a pas de répertoire central à la fin. Cela pourrait être corrigé avec zip
's -FF
mais j'ai décidé de changer un peu les en-têtes et de le convertir en fichier gzip. Le (PK)zip et le gzip utilisent tous les deux le même fichier déflater L'algorithme de compression et même les sommes de contrôle CRC-32 semblent être compatibles.
Voici un exemple de la façon de télécharger un fichier aléatoire à partir de l'archive de Xonotic disponible à l'adresse suivante http://dl.xonotic.org/xonotic-0.8.1.zip , le décompresser et l'enregistrer dans un fichier local :
bash get_file_from_remote_zip.sh http://dl.xonotic.org/xonotic-0.8.1.zip Xonotic/source/darkplaces/mprogdefs.h | gzip -d >mprogdefs.h
Le premier bloc de code est un script Python (2) que j'ai appelé list_remote_zip.py
. Ainsi, si vous avez installé Python, vous pouvez le lancer et lui passer l'URL du fichier zip comme argument de ligne de commande, comme suit : python list_remote_zip.py http://dl.xonotic.org/xonotic-0.8.1.zip
Montez le fichier ZIP distant via un système de fichiers virtuel soutenu par HTTP, puis utilisez la commande unzip standard sur celui-ci. De cette façon, les appels d'E/S de l'utilitaire unzip sont traduits en GETs de la gamme HTTP, ce qui signifie que seuls les morceaux du fichier ZIP que vous voulez sont transférés sur le réseau.
Voici un exemple pour Linux utilisant HTTPFS un système de fichiers virtuel très léger basé sur FUSE. Il existe des outils similaires pour Windows. Les langages de programmation comme Python et Java fournissent également des E/S HTTP, il suffit de les combiner de manière appropriée avec leur logique de lecture ZIP.
Obtenir/construire httpfs :
$ wget http://sourceforge.net/projects/httpfs/files/httpfs/1.06.07.02
$ tar -xjf httpfs_1.06.07.10.tar.bz2
$ rm httpfs
$ ./make_httpfs
Monter un fichier ZIP distant et en extraire un fichier :
$ mkdir mount_pt
$ sudo ./httpfs http://example.com/zipfile.zip mount_pt
$ ls mount_pt
zipfile.zip
$ unzip -p mount_pt/zipfile.zip the_file_I_want.txt > the_file_I_want.txt
$ sudo umount mount_pt
(besoin de sudo
peut varier en fonction de la configuration de FUSE sur votre système).
Bien sûr, vous pouvez aussi utiliser d'autres outils que ceux de la ligne de commande.
En supposant que le serveur prenne en charge la reprise des téléchargements, il serait en théorie possible d'écrire un client qui fasse cela - saisir un bloc suffisamment gros vers la fin pour obtenir le répertoire, puis l'utiliser pour déterminer ce que vous devez saisir pour obtenir réellement les données - commencer simplement à télécharger à cette position et arrêter quand vous avez assez de données. Cela fait tellement longtemps que je ne me souviens plus s'il y a un moyen de trouver le début du répertoire autrement que par la force brute.
Je n'ai jamais entendu parler d'un tel client et je ne peux pas imaginer pourquoi il serait développé - si ce sont des données qui seraient raisonnablement téléchargées en morceaux, alors pourquoi le webmaster les stocke dans un gros fichier zip ???
Il y a des cas où vous téléchargez un gros fichier zip et certains fichiers sont corrompus, alors si cette solution existe, cela me facilitera la vie de ne télécharger que les fichiers corrompus.
@habibhassani En d'autres termes, le fait qu'il s'agisse d'un fichier zip n'est pas vraiment pertinent, vous voulez juste récupérer un morceau endommagé d'un fichier.
SystemesEZ est une communauté de sysadmins où vous pouvez résoudre vos problèmes et vos doutes. Vous pouvez consulter les questions des autres sysadmins, poser vos propres questions ou résoudre celles des autres.
0 votes
La question est donc vraiment générique, mais généralement pas. Avec certains formats compressés, vous pouvez être en mesure d'extraire une partie de leur contenu à partir du fichier incomplet.
rar x --kb myincompletefile.rar
. Pour7zip
voir même cette réponse . De quel type de serveur s'agit-il ? Utilisez-vouszip
juste pour dire compressé ou vous vous référez strictement àzip
des fichiers ?0 votes
Je parle d'un fichier mis en ligne pour le téléchargement via le protocole http ou ftp ou même un torrent, et je me réfère strictement au fichier .zip.
0 votes
Alors j'ai bien peur que votre réponse soit いいえ . :-( Mais vous pouvez toujours commencer à télécharger, essayer de réparer/extraire la partie partielle, et voir s'il y a ce dont vous avez besoin.... Si vous vous référez à la distribution de logiciels avec un fichier zip unique sous ftp, parfois ils ont la "ouvert" version aussi que vous pouvez explorer comme un chemin normal ... Je pense à quelque chose comme CTAN des miroirs...
0 votes
Merci beaucoup pour les infos, j'aimerais pouvoir mettre votre commentaire comme utile mais je suis niveau 1
0 votes
Je pense qu'une telle chose serait possible, en téléchargeant l'en-tête, puis en utilisant les options HTTP liées à la reprise d'un téléchargement partiel. Si vous êtes un programmeur, vous pouvez peut-être faire en sorte que cela fonctionne. Cependant, je n'ai jamais entendu parler d'une telle opération dans la pratique. L'obtention d'une partie seulement d'un fichier est quelque chose qui se fait couramment avec les médias (audio/vidéo), et qui peut utiliser la technologie du "streaming" (historiquement, d'autres protocoles, ou des modules complémentaires de navigateur web comme Flash ; pour le moment, je ne suis pas sûr que HTML5 puisse faire quelque chose de similaire). Donc, puisque je n'ai jamais entendu parler d'une telle pratique, je suis d'accord avec les réponses "non".
0 votes
J'ai ensuite trouvé [ stackoverflow.com/a/15321699/4411648 ] (Téléchargement de quelques données à partir d'un fichier zip) qui semble discuter de ce que je faisais, en pratique, dans les deux premières phrases (de mon commentaire ci-dessus).
0 votes
@TOOGAM, super. Je ne me serais pas attendu à ce qu'il y ait des systèmes de fichiers fusionnés sur HTTP. Très chouette. En procédant de cette manière, la commande unzip a un accès complet à l'ensemble du fichier, dans le but de le décrypter, mais ne récupère que les bits nécessaires (comme les alias). Je me demande quel est le support des serveurs web pour HTTPFS.
0 votes
Merci pour votre rediffusion. du point de vue de la programmation, c'est un service facile à concevoir, je me demande pourquoi les sites de stockage n'ont pas proposé cette option. cela leur permettrait d'économiser de la bande passante et de nous faire gagner du temps.