Eu escrevi um script Python list_remote_zip.py
que pode listar arquivos em um arquivo zip acessível por 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()
Ele não usa o diretório central do arquivo zip, que está perto do final do arquivo. Em vez disso, ele vai desde o início e analisa cabeçalhos locais individuais e pula a carga útil, esperando pousar em outro cabeçalho. Ele envia uma nova solicitação toda vez que precisa pular para um deslocamento. Obviamente, isso só funciona com servidores que suportam o cabeçalho Range
HTTP.
Só precisa ser passado o URL para o arquivo zip como um argumento de linha de comando. Exemplo de uso e saída deve ser algo como isto:
$ 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
...
Para baixar um dos arquivos, eu escrevi um script get_file_from_remote_zip.sh
bash ainda mais feio ao redor dele que usa 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 '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
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()
$ 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
...
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 '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
%pre%%pre%%pre%%pre%%pre%\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"
%pre%%pre%\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"
São necessários dois argumentos. A primeira é a URL do arquivo zip e a segunda o arquivo a ser extraído. O nome do arquivo a ser extraído deve ser completo e exatamente como aparece na saída do script list_remote_zip.py
Python anterior, que ele usa para obter algumas informações sobre o arquivo. Em seguida, ele usa wget
para fazer o download no deslocamento correto com o comprimento correto. Ele salva o zip "slice" em um arquivo temporário, que é usado para gerar um arquivo gzip
-formatted, que pode ser canalizado e descompactado com gzip
. O "slice" em si não é um arquivo zip válido porque não possui um diretório central no final. Pode ser corrigido com a opção zip
-FF
, mas eu decidi mudar um pouco os cabeçalhos e convertê-los em um arquivo gzip. Ambos (PK) zip e gzip usam o mesmo algoritmo de compressão deflacionar e até mesmo as sondas de verificação CRC-32 parecem compatíveis. / p>
Aqui está um exemplo de como baixar um arquivo aleatório do arquivo do Xonotic disponível no link , descomprimir e salve-o em um arquivo local:
%pre%