I was having issues downloading a file with ftplib in python. Using the simple way with the following code was not working. The code did not stop.
with open('README', 'wb') as fp:
ftp.retrbinary('RETR README', fp.write)
So i found this solution:
class ImplicitFTP_TLS(ftplib.FTP_TLS):
"""FTP_TLS subclass that automatically wraps sockets in SSL to support implicit FTPS."""
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self._sock = None
@property
def sock(self):
"""Return the socket."""
return self._sock
@sock.setter
def sock(self, value):
"""When modifying the socket, ensure that it is ssl wrapped."""
if value is not None and not isinstance(value, ssl.SSLSocket):
value = self.context.wrap_socket(value)
self._sock = value
def setInterval(interval, times = -1):
# This will be the actual decorator,
# with fixed interval and times parameter
def outer_wrap(function):
# This will be the function to be
# called
def wrap(*args, **kwargs):
stop = threading.Event()
# This is another function to be executed
# in a different thread to simulate setInterval
def inner_wrap():
i = 0
while i != times and not stop.isSet():
stop.wait(interval)
function(*args, **kwargs)
i += 1
t = threading.Timer(0, inner_wrap)
t.daemon = True
t.start()
return stop
return wrap
return outer_wrap
class PyFTPclient:
# https://github.com/keepitsimple/pyFTPclient
def __init__(self, host, port = 21, login = 'anonymous', passwd = 'anonymous', monitor_interval = 30):
self.host = host
self.port = port
self.login = login
self.passwd = passwd
self.monitor_interval = monitor_interval
self.ptr = None
self.max_attempts = 15
self.waiting = True
def get_files_names(self, dir_score='/'):
"""
This function returns a list of the files from a directory.
Parameters
----------
dir_score : str, default root directory
The directory path.
Returns
-------
list
List with the files from the directory.
"""
ftp_client = ImplicitFTP_TLS()
ftp_client.connect(host=self.host, port=self.port)
ftp_client.login(user=self.login, passwd=self.passwd)
ftp_client.prot_p()
# ftp_client.dir()
ftp_client.cwd(dir_score) #Muda diretorio
files = []
ftp_client.dir(files.append)
ftp_client.quit()
return files
def DownloadFile(self, dst_filename, local_filename = None):
res = ''
if local_filename is None:
local_filename = dst_filename.split('/')[-1]
with open(local_filename, 'w+b') as f:
self.ptr = f.tell()
@setInterval(self.monitor_interval)
def monitor():
if not self.waiting:
i = f.tell()
if self.ptr < i:
logging.debug("%d - %0.1f Kb/s" % (i, (i-self.ptr)/(1024*self.monitor_interval)))
self.ptr = i
else:
ftp.close()
def connect():
ftp.connect(self.host, self.port)
ftp.login(self.login, self.passwd)
ftp.prot_p()
# optimize socket params for download task
ftp.sock.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)
ftp.sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_KEEPINTVL, 75)
ftp.sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_KEEPIDLE, 60)
ftp = ImplicitFTP_TLS()
ftp.set_debuglevel(2)
ftp.set_pasv(True)
connect()
ftp.voidcmd('TYPE I')
dst_filesize = ftp.size(dst_filename)
mon = monitor()
while dst_filesize > f.tell():
try:
connect()
self.waiting = False
# retrieve file from position where we were disconnected
res = ftp.retrbinary('RETR %s' % dst_filename, f.write) if f.tell() == 0 else \
ftp.retrbinary('RETR %s' % dst_filename, f.write, rest=f.tell())
except:
self.max_attempts -= 1
if self.max_attempts == 0:
mon.set()
logging.exception('')
raise
self.waiting = True
logging.info('waiting 30 sec...')
time.sleep(30)
logging.info('reconnect')
mon.set() #stop monitor
ftp.close()
if not res.startswith('226 Transfer complete'):
logging.error('Downloaded file {0} is not full.'.format(dst_filename))
# os.remove(local_filename)
return None
return 1
obj = PyFTPclient(FTP_HOST, port=FTP_PORT, login=FTP_USER, passwd=FTP_PWD)
obj.DownloadFile(dst_filename=path_file_name_to_download, local_filename=path_local_filename)
Now, i am having the same problem trying upload files. The way to do so i found in internet is:
f = open(fullname, "rb")
ftp.storbinary('STOR ' + name, f)
But is not working for me with the same problem as before. The code does not stop. I tested with small files and the last output it gives are:
*cmd* 'STOR file.csv'
*put* 'STOR file.csv\r\n'
*get* '150 Opening BINARY mode data connection.\n'
*resp* '150 Opening BINARY mode data connection.'
and does not finish the code.