Also habe ich es selbst heraus :)
from ftplib import *
from threading import *
from shutil import *
import os
num_parts = 20
FTP_server = 'ftp.example.com'
FTP_user = 'mark'
FTP_password = 'password'
FTP_directory = '/foo/bar'
FTP_file = 'foo.bar'
class Done(Exception):
pass
def open_ftp():
ftp = FTP(FTP_server, FTP_user, FTP_password)
ftp.cwd(FTP_directory)
return ftp
def go():
ftp = open_ftp()
filesize = ftp.size(FTP_file)
print 'filesize: ' + str(filesize)
ftp.quit()
chunk_size = filesize/num_parts
last_chunk_size = filesize - (chunk_size * (num_parts - 1))
downloaders = []
for i in range(num_parts):
if i == (num_parts - 1):
this_chunk_size = last_chunk_size
else:
this_chunk_size = chunk_size
downloaders.append(Downloader(i, chunk_size * i, this_chunk_size))
for downloader in downloaders:
downloader.thread.join()
with open(FTP_file, 'w+b') as f:
for downloader in downloaders:
copyfileobj(open(downloader.part_name, 'rb'), f)
class Downloader:
thread_number = 0
def __init__(self, part_number, part_start, part_size):
self.filename = FTP_file
self.part_number = part_number
self.part_name = 'part' + str(self.part_number)
self.part_start = part_start
self.part_size = part_size
Downloader.thread_number += 1
self.thread_number = Downloader.thread_number
self.ftp = open_ftp()
self.thread = Thread(target=self.receive_thread)
self.thread.start()
def receive_thread(self):
try:
self.ftp.retrbinary('RETR '+self.filename, self.on_data, 100000, self.part_start)
except Done:
pass
def on_data(self, data):
with open(self.part_name, 'a+b') as f:
f.write(data)
if os.path.getsize(self.part_name) >= self.part_size:
with open(self.part_name, 'r+b') as f:
f.truncate(self.part_size)
raise Done
go()
So erfuhr ich, dass Rückruf von retrbinary die tatsächlichen binären Daten, die es erhält. Also für jeden Thread, ich eine Datei erstellen und diese Binärdaten aus dem Rückruf anfügen, bis die Größe der Datei größer als die erwartete Größe ist, dann schneiden wir das Extra. Wenn alle Threads abgeschlossen sind, werden die Dateien verkettet und eine Datei mit dem ursprünglichen Dateinamen wird erstellt. Filesize und Sha256 sind fertig und confirmed es funktioniert. :)
Der Code von RichieHindle
Für eine große Datei angepasst wurde ich folgende Fehlermeldung zu sehen Datei "/python/2.7.3/lib/python2.7/ftplib.py", Linie 555, in Größe resp = self.sendcmd ('SIZE' + Dateiname) Datei "/python/2.7.3/lib/python2.7/ftplib.py", Zeile 244, in sendcmd Rückgabe self.getresp() Datei " /python/2.7.3/lib/python2.7/ftplib.py ", Zeile 219, in getresp raise error_perm, bzw. ftplib.error_perm: 550 foo.tgz: zu groß für Typ A SIZE. Wie kann ich dieses Problem umgehen? ftp.sendcmd ('binary') funktioniert nicht – ghostkadost
@gostkadost der Fehler, der ausgelöst wird, ist mit Berechtigungen (550) zu tun, stellen Sie sicher, dass Sie ihm den richtigen Pfad geben. –