用多线程分块从ftp下载文件!

用多线程分块从ftp下载文件![复制链接]

  
跳转到指定楼层
1#
发表于 2008-4-21 16:57:08 | 只看该作者 | 倒序浏览
应昨天 hongfu 的要求,搞了一段用多线程从ftp上分块同时下载文件的简单例子。
  1. #-*- encoding: gb18030 -*-
  2. import ftplib, string
  3. import os, sys
  4. import threading

  5. class MyFTP:
  6.     def __init__(self, host='', user='', passwd=''):        
  7.         self.host = host
  8.         self.user = user
  9.         self.passwd = passwd        
  10.         self.filename = ''
  11.         
  12.         self.ftp = ftplib.FTP(host,user,passwd)
  13.    
  14.     def download_by_thread(self, filename, threadnum=1, blocksize=8192):
  15.         self.filename = filename
  16.         # 获取文件名
  17.         onlyname = os.path.basename(filename)
  18.         cmd = "SIZE "+filename
  19.         # 取得要下载的文件的大小
  20.         ret = self.ftp.sendcmd(cmd)
  21.         
  22.         self.ftp.quit()
  23.         # 计算用多线程下载时,每一个线程应该下载的大小
  24.         fsize = int(string.split(ret)[1])
  25.         print 'file', filename, 'size:', fsize        
  26.       
  27.         rest = None
  28.         bsize = fsize / threadnum
  29.         
  30.         # 创建线程
  31.         threads= []
  32.         for i in range(0, threadnum-1):
  33.             begin = bsize * i
  34.             print i, begin, bsize
  35.             tp = threading.Thread(target=self.download_file, args=(i, filename,begin,bsize,blocksize,rest,))
  36.             threads.append(tp)
  37.         
  38.         have1 = bsize * threadnum
  39.         have2 = fsize - have1
  40.         lastsize = bsize + have2        
  41.         begin = bsize * (threadnum-1)
  42.         print threadnum-1, begin, lastsize
  43.         tp = threading.Thread(target=self.download_file, args=(threadnum-1, filename, begin,lastsize,blocksize,rest,))
  44.         threads.append(tp)
  45.         
  46.         print 'threads:', len(threads)        
  47.         
  48.         for t in threads:
  49.             t.start()
  50.             
  51.         for t in threads:
  52.             t.join()
  53.         
  54.         # 每个线程都下载完成了,合并临时文件为一个文件
  55.         fw = open(onlyname, "wb")
  56.         
  57.         for i in range(0, threadnum):
  58.             fname = onlyname+'.part.'+str(i)
  59.             print fname
  60.             if not os.path.isfile(fname):
  61.                 print 'not found', fname
  62.                 continue
  63.             f1 = open(fname, 'rb')
  64.             while 1:
  65.                 data = f1.read(8192)               
  66.                 if not len(data):
  67.                     break
  68.                 fw.write(data)            
  69.             f1.close()
  70.             os.remove(fname)        
  71.         fw.close()
  72.         print 'all ok'
  73.         
  74.     def download_file(self, inx, filename, begin=0, size=0, blocksize=8192, rest=None):
  75.         onlyname = os.path.basename(filename)
  76.         tname = threading.currentThread().getName()
  77.         #inx = string.split(tname, '-')[-1]
  78.         # 新建一个连接来下载,每个线程一个连接,注意这里没有考虑有些ftp服务器限制一个ip只能有多少连接的情况。
  79.         myftp = ftplib.FTP(self.host,self.user,self.passwd)
  80.         # 创建临时文件
  81.         fp = open(onlyname+'.part.'+str(inx), 'wb')
  82.         #fp.seek(begin)
  83.         
  84.         callback = fp.write
  85.         
  86.         haveread = 0
  87.         myftp.voidcmd('TYPE I')
  88.         # 告诉服务器要从文件的哪个位置开始下载
  89.         cmd1 = "REST "+str(begin)
  90.         print tname, cmd1
  91.         ret = myftp.sendcmd(cmd1)
  92.         # 开始下载
  93.         cmd = "RETR "+filename
  94.         conn = myftp.transfercmd(cmd, rest)
  95.         readsize = blocksize
  96.         while 1:            
  97.             if size > 0:
  98.                 last = size - haveread
  99.                 if last > blocksize:
  100.                     readsize = blocksize
  101.                 else:
  102.                     readsize = last
  103.             data = conn.recv(readsize)
  104.             if not data:
  105.                 break
  106.             #callback(fp, data)   
  107.             # 已经下载的数据长度        
  108.             haveread = haveread + len(data)
  109.             # 只能下载指定长度的数据,下载到就退出
  110.             if haveread > size:
  111.                 print tname, 'haveread:', haveread, 'size:', size
  112.                 hs = haveread - size
  113.                 callback(data[:hs])
  114.                 break
  115.             elif haveread == size:
  116.                 callback(data)
  117.                 print tname, 'haveread:', haveread
  118.                 break
  119.                
  120.             callback(data)
  121.             
  122.         conn.close()
  123.         fp.close()
  124.         try:
  125.             ret =  myftp.getresp()
  126.         except Exception, e:
  127.             print tname,e
  128.             
  129.         myftp.quit()
  130.         
  131.         return ret   


  132. ftp = MyFTP("127.0.0.1", 'anonymous', '123')
  133. filename='/incoming/cygwin.zip'
  134. ftp.download_by_thread(filename, 10)
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值