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!

Baixe aqui: disco_virtual.py

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!

Leave a Reply