FTPLIB com progresso no upload
Desde que comecei a me aventurar com python tinha a seguinte dúvida:
“Como fazer upload com ftplib.FTP exibindo o progresso?”
Hoje resolvi, com mais maturidade na linguagem, tentar resolver tal problema novamente.
A base da solução foi como a dica da lista python-brasil:
herdar a classe FTP, do módulo ftplib e sobrescrever o método storbinary.
O “pulo do gato” é um pequeno detalhe que se aprende com a vida:
Acontece que o método storbinary possui um parametro “blocksize” que determina de quantos em quantos bytes o arquivo será lido dentro de um loop while que só acaba quando quando todo o arquivo for varrido e enviado.
Aí vem o grande lance:
ao invés de fazer o storbinary simplesmente dar um return quando todo o arquivo for enviado, fez-se necessário usar um generator yield, para tornar o storbinary iterável, retornando a cada loop uma tupla contendo 2 itens: a quantidade de bytes já enviada e o total de bytes do arquivo.
Daí basta iterar sobre o storbinary e usar as informações da maneira necessária.
Essa maneira é interessante pois pode-se generalizar o uso da informação de porcentagem enviada.
No meu caso, usei numa GtkProgressbar.
O código do ftplib.FTP modificado ficou assim:
[python]
class progress_FTP(ftplib.FTP):
…. def storbinary(self, cmd, fp, blocksize=8192, use_percent=False):
…….. length = len(fp.read())
…….. percent = float(length) * 0.01
…….. fp.seek(0)
…….. cntblock = 0
…….. self.voidcmd(’TYPE I’)
…….. conn = self.transfercmd(cmd)
…….. while 1:
………… buf = fp.read(blocksize)
………… if use_percent:
……………. yield (float(int(cntblock / percent)),100)
………… else:
……………. yield (cntblock,length)
………… cntblock += len(buf)
………… conn.send(buf)
………… if not buf:
……………. conn.close()
……………. break
[/python]
Para utilizar é bem tranquilo:
[python]
con = progress_FTP()
con.connect(’ftp.servidor.com’)
con.login(’admin’,'123456′)
arquivo = ‘/home/pythonist/ftp.py’
fopen = open(arquivo ,’rb’)
for percentual,total in con.storbinary(’STOR /web/disco/enviados/%s’%arquivo, fopen,use_percent=True):
…. print “Enviado”, percentual, “%”
else:
…. print “FIM!”
fopen.close()
[/python]
No final das contas aproveitei para dar uma limpeza geral no meu uploader e enfim divulgar para que todos aproveitem!
Agora sim está bem limpo!
Faltou um tratamento de erros bem feito, mas de resto, acho que tá legal!
Aproveite e coloque-o no em algum lugar do seu PATH e crie um atalho no nautilus-actions.
Ah! Eu sei que faltou um pouco de PEP-0008 nos códigos!