pbootcms网站模板|日韩1区2区|织梦模板||网站源码|日韩1区2区|jquery建站特效-html5模板网

Python:文件下載成功后,使用 ftplib 下載文件永遠

Python: File download using ftplib hangs forever after file is successfully downloaded(Python:文件下載成功后,使用 ftplib 下載文件永遠掛起)
本文介紹了Python:文件下載成功后,使用 ftplib 下載文件永遠掛起的處理方法,對大家解決問題具有一定的參考價值,需要的朋友們下面隨著小編來一起學習吧!

問題描述

我一直在嘗試解決從 ftp/ftps 下載文件時出現的問題.文件下載成功,但文件下載完成后不執行任何操作.沒有發生可以提供有關該問題的更多信息的錯誤.我嘗試在 stackoverflow 上搜索這個,發現這個 鏈接 談到了類似的問題陳述,看起來我面臨類似的問題,但我不確定.在解決問題時需要更多幫助.

I have been trying to troubleshoot an issue where in when we are downloading a file from ftp/ftps. File gets downloaded successfully but no operation is performed post file download completion. No error has occurred which could give more information about the issue. I tried searching for this on stackoverflow and found this link which talks about similar problem statement and looks like I am facing similar issue, though I am not sure. Need little more help in resolving the issue.

我嘗試將 FTP 連接超時設置為 60 分鐘,但幫助較少.在此之前,我使用的是 ftplib 的 retrbinary(),但同樣的問題發生在那里.我嘗試傳遞不同的塊大小和窗口大小,但同樣的問題是可重現的.

I tried setting the FTP connection timeout to 60mins but of less help. Prior to this I was using retrbinary() of the ftplib but same issue occurs there. I tried passing different blocksize and windowsize but with that also issue was reproducible.

我正在嘗試從 AWS EMR 集群下載大小約為 3GB 的文件.示例代碼如下.

I am trying to download the file of size ~3GB from AWS EMR cluster. Sample code is written below.

    def download_ftp(self, ip, port, user_name, password, file_name, target_path):
    try:
        os.chdir(target_path)
        ftp = FTP(host=ip)
        ftp.connect(port=int(port), timeout=3000)
        ftp.login(user=user_name, passwd=password)

        if ftp.nlst(file_name) != []:
            dir = os.path.split(file_name)
            ftp.cwd(dir[0])
            for filename in ftp.nlst(file_name):
                sock = ftp.transfercmd('RETR ' + filename)

                def background():
                    fhandle = open(filename, 'wb')
                    while True:
                        block = sock.recv(1024 * 1024)
                        if not block:
                            break
                        fhandle.write(block)
                    sock.close()

                t = threading.Thread(target=background)
                t.start()
                while t.is_alive():
                    t.join(60)
                    ftp.voidcmd('NOOP')
                logger.info("File " + filename + " fetched successfully")
            return True
        else:
            logger.error("File " + file_name + " is not present in FTP")

    except Exception, e:
        logger.error(e)
        raise

上述鏈接中建議的另一個選項是在下載小塊文件后關閉連接,然后重新啟動連接.有人可以建議如何實現這一點,不確定如何在關閉連接之前從上次停止文件下載的同一點恢復下載.這種方法是否可以完全證明下載整個文件.

Another option suggested in the above mentioned link is to close the connection post downloading small chunk of the file and then restart the connection. Can someone suggest how can this be achieved, not sure how to resume the download from the same point where the file download was stopped last time before closing the connection. Will this method be full proof of downloading the entire file.

我對 FTP 服務器級別的超時設置了解不多,因此不知道需要更改什么以及如何更改.我基本上想寫一個通用的 FTP 下載器,它可以幫助從 FTP/FTPS 下載文件.

I don't know much about FTP server level timeout settings so didn't know what and how it needs to be altered. I basically want to write a generic FTP down-loader which can help in downloading the files from FTP/FTPS.

當我使用 ftplib 的 retrbinary() 方法并將調試級別設置為 2 時.

When I use retrbinary() method of ftplib and set debug level to 2.

ftp.set_debuglevel(2)
ftp.retrbinary('RETR ' + filename, fhandle.write)

正在打印以下日志.

cmd 'TYPE I'put 'TYPE I 'get '200 類型設置為 I. 'resp '200 類型設置為 I.'cmd 'PASV'put 'PASV 'get '227 進入被動模式 (64,27,160,28,133,251). 'resp '227 進入被動模式(64,27,160,28,133,251).cmd 'RETR FFFT_BRA_PM_R_201711.txt'put 'RETR FFFT_BRA_PM_R_201711.txt 'get '150 打開 FFFT_BRA_PM_R_201711.txt 的 BINARY 模式數據連接. 'resp '150 打開 FFFT_BRA_PM_R_201711.txt 的 BINARY 模式數據連接.'

cmd 'TYPE I' put 'TYPE I ' get '200 Type set to I. ' resp '200 Type set to I.' cmd 'PASV' put 'PASV ' get '227 Entering Passive Mode (64,27,160,28,133,251). ' resp '227 Entering Passive Mode (64,27,160,28,133,251).' cmd 'RETR FFFT_BRA_PM_R_201711.txt' put 'RETR FFFT_BRA_PM_R_201711.txt ' get '150 Opening BINARY mode data connection for FFFT_BRA_PM_R_201711.txt. ' resp '150 Opening BINARY mode data connection for FFFT_BRA_PM_R_201711.txt.'

推薦答案

在做任何事情之前,請注意您的連接存在嚴重問題,診斷并修復它比解決它要好得多.但有時,您只需要處理損壞的服務器,甚至發送保活也無濟于事.那么,你能做什么呢?

Before doing anything, note that there is something very wrong with your connection, and diagnosing that and getting it fixed is far better than working around it. But sometimes, you just have to deal with a broken server, and even sending keepalives doesn't help. So, what can you do?

訣竅是一次下載一個塊,然后中止下載,或者,如果服務器無法處理中止,則關閉并重新打開連接.

The trick is to download a chunk at a time, then abort the download—or, if the server can't handle aborting, close and reopen the connection.

請注意,我正在使用 ftp://speedtest.tele2.net/5MB 測試以下所有內容.zip,希望這不會導致一百萬人開始攻擊他們的服務器.當然,您需要使用實際的服務器對其進行測試.

Note that I'm testing everything below with ftp://speedtest.tele2.net/5MB.zip, which?hopefully this doesn't cause a million people to start hammering their servers. Of course you'll want to test it with your actual server.

整個解決方案當然依賴于能夠恢復傳輸的服務器,而并非所有服務器都能做到這一點——尤其是當您處理嚴重損壞的東西時.所以我們需要對此進行測試.請注意,此測試將非常緩慢,并且在服務器上非常繁重,因此不要使用 3GB 文件進行測試;找到更小的東西.此外,如果您可以在其中放置可讀的內容,這將有助于調試,因為您可能會在十六進制編輯器中比較文件時遇到困難.

The entire solution of course relies on the server being able to resume transfers, which not all servers can do—especially when you're dealing with something badly broken. So we'll need to test for that. Note that this test will be very slow, and very heavy on the server, so do not testing with your 3GB file; find something much smaller. Also, if you can put something readable there, it will help for debugging, because you may be stuck comparing files in a hex editor.

def downit():
    with open('5MB.zip', 'wb') as f:
        while True:
            ftp = FTP(host='speedtest.tele2.net', user='anonymous', passwd='test@example.com')
            pos = f.tell()
            print(pos)
            ftp.sendcmd('TYPE I')
            sock = ftp.transfercmd('RETR 5MB.zip', rest=pos)
            buf = sock.recv(1024 * 1024)
            if not buf:
                return
            f.write(buf)

您可能不會一次獲得 1MB,而是 8KB 以下.假設您看到的是 1448,然后是 2896、4344 等.

You will probably not get 1MB at a time, but instead something under 8KB. Let's assume you're seeing 1448, then 2896, 4344, etc.

  • 如果您從 REST 中獲得異常,則服務器不會處理恢復 - 放棄,您將被淹沒.
  • 如果文件超出實際文件大小,請點擊 ^C,然后在十六進制編輯器中檢查.
    • 如果您一遍又一遍地看到相同的 1448 字節或其他任何內容(您看到它打印出來的數量),那您就完蛋了.
    • 如果您有正確的數據,但在每個 1448 字節的塊之間有額外的字節,那實際上是可以修復的.如果您遇到這個問題并且無法弄清楚如何使用 f.seek 來解決它,我可以解釋——但您可能不會遇到它.
    • If you get an exception from the REST, the server does not handle resuming—give up, you're hosed.
    • If the file goes on past the actual file size, hit ^C, and check it in a hex editor.
      • If you see the same 1448 bytes or whatever (the amount you saw it printing out) over and over again, again, you're hosed.
      • If you have the right data, but with extra bytes between each chunk of 1448 bytes, that's actually fixable. If you run into this and can't figure out how to fix it by using f.seek, I can explain—but you probably won't run into it.

      我們可以做的一件事是嘗試中止下載并且重新連接.

      One thing we can do is try to abort the download and not reconnect.

      def downit():
          with open('5MB.zip', 'wb') as f:
              ftp = FTP(host='speedtest.tele2.net', user='anonymous', passwd='test@example.com')
              while True:
                  pos = f.tell()
                  print(pos)
                  ftp.sendcmd('TYPE I')
                  sock = ftp.transfercmd('RETR 5MB.zip', rest=pos)
                  buf = sock.recv(1024 * 1024)
                  if not buf:
                      return
                  f.write(buf)
                  sock.close()
                  ftp.abort()
      

      您將要嘗試多種變體:

      • 沒有sock.close.
      • 沒有ftp.abort.
      • ftp.abort 之后使用 sock.close.
      • sock.close 之后使用 ftp.abort.
      • 上述所有四個重復,TYPE I 移到循環之前而不是每次.
      • No sock.close.
      • No ftp.abort.
      • With sock.close after ftp.abort.
      • With ftp.abort after sock.close.
      • All four of the above repeated with TYPE I moved to before the loop instead of each time.

      有些會引發異常.其他人只會看起來永遠掛起.如果這對所有 8 個都是真的,我們需要放棄中止.但如果其中任何一個有效,那就太好了!

      Some will raise exceptions. Others will just appear to hang forever. If that's true for all 8 of them, we need to give up on aborting. But if any of them works, great!

      另一種加快速度的方法是在中止或重新連接之前一次下載 1MB(或更多).只需替換此代碼:

      The other way to speed things up is to download 1MB (or more) at a time before aborting or reconnecting. Just replace this code:

      buf = sock.recv(1024 * 1024)
      if buf:
          f.write(buf)
      

      用這個:

      chunklen = 1024 * 1024
      while chunklen:
          print('   ', f.tell())
          buf = sock.recv(chunklen)
          if not buf:
              break
          f.write(buf)
          chunklen -= len(buf)
      

      現在,您不再為每次傳輸讀取 1442 或 8192 字節,而是每次傳輸最多讀取 1MB.試著把它推得更遠.

      Now, instead of reading 1442 or 8192 bytes for each transfer, you're reading up to 1MB for each transfer. Try pushing it farther.

      例如,如果您的下載在 10MB 時失敗,而您問題中的 keepalive 代碼將大小增加到 512MB,但對于 3GB 來說還是不夠,您可以將兩者結合起來.使用 keepalive 一次讀取 512MB,然后中止或重新連接并讀取下一個 512MB,直到完成.

      If, say, your downloads were failing at 10MB, and the keepalive code in your question got things up to 512MB, but it just wasn't enough for 3GB—you can combine the two. Use keepalives to read 512MB at a time, then abort or reconnect and read the next 512MB, until you're done.

      這篇關于Python:文件下載成功后,使用 ftplib 下載文件永遠掛起的文章就介紹到這了,希望我們推薦的答案對大家有所幫助,也希望大家多多支持html5模板網!

      【網站聲明】本站部分內容來源于互聯網,旨在幫助大家更快的解決問題,如果有圖片或者內容侵犯了您的權益,請聯系我們刪除處理,感謝您的支持!

相關文檔推薦

Why I cannot make an insert to Python list?(為什么我不能插入 Python 列表?)
Insert a column at the beginning (leftmost end) of a DataFrame(在 DataFrame 的開頭(最左端)插入一列)
Python psycopg2 not inserting into postgresql table(Python psycopg2 沒有插入到 postgresql 表中)
list extend() to index, inserting list elements not only to the end(list extend() 索引,不僅將列表元素插入到末尾)
How to add element in Python to the end of list using list.insert?(如何使用 list.insert 將 Python 中的元素添加到列表末尾?)
TypeError: #39;float#39; object is not subscriptable(TypeError:“浮動對象不可下標)
主站蜘蛛池模板: 长城人品牌官网| 标策网-专注公司商业知识服务、助力企业发展 | 陕西安玻璃自动感应门-自动重叠门-磁悬浮平开门厂家【捷申达门业】 | 江苏全风,高压风机,全风环保风机,全风环形高压风机,防爆高压风机厂家-江苏全风环保科技有限公司(官网) | 承插管件_不锈钢承插管件_锻钢高压管件-温州科正阀门管件有限公司 | 猪I型/II型胶原-五克隆合剂-细胞冻存培养基-北京博蕾德科技发展有限公司 | 大米加工设备|大米加工机械|碾米成套设备|大米加工成套设备-河南成立粮油机械有限公司 | 天津电机维修|水泵维修-天津晟佳机电设备有限公司 | 广东青藤环境科技有限公司-水质检测| 泉州陶瓷pc砖_园林景观砖厂家_石英砖地铺石价格 _福建暴风石英砖 | 祝融环境-地源热泵多恒系统高新技术企业,舒适生活环境缔造者! | 北京康百特科技有限公司-分子蒸馏-短程分子蒸馏设备-实验室分子蒸馏设备 | 世界箱包品牌十大排名,女包小众轻奢品牌推荐200元左右,男包十大奢侈品牌排行榜双肩,学生拉杆箱什么品牌好质量好 - Gouwu3.com | 高速混合机_锂电混合机_VC高效混合机-无锡鑫海干燥粉体设备有限公司 | 洛阳永磁工业大吊扇研发生产-工厂通风降温解决方案提供商-中实洛阳环境科技有限公司 | 南京租车,南京汽车租赁,南京包车,南京会议租车-南京七熹租车 | 蓝牙音频分析仪-多功能-四通道-八通道音频分析仪-东莞市奥普新音频技术有限公司 | 除甲醛公司-甲醛检测-广西雅居环境科技有限公司 | 低噪声电流前置放大器-SR570电流前置放大器-深圳市嘉士达精密仪器有限公司 | 压滤机滤板_厢式_隔膜_板框压滤机滤板厂家价格型号材质-大凯环保 | 钢衬玻璃厂家,钢衬玻璃管道 -山东东兴扬防腐设备有限公司 | 武汉高温老化房,恒温恒湿试验箱,冷热冲击试验箱-武汉安德信检测设备有限公司 | KBX-220倾斜开关|KBW-220P/L跑偏开关|拉绳开关|DHJY-I隔爆打滑开关|溜槽堵塞开关|欠速开关|声光报警器-山东卓信有限公司 | 深圳宣传片制作_产品视频制作_深圳3D动画制作公司_深圳短视频拍摄-深圳市西典映画传媒有限公司 | 中空玻璃生产线,玻璃加工设备,全自动封胶线,铝条折弯机,双组份打胶机,丁基胶/卧式/立式全自动涂布机,玻璃设备-山东昌盛数控设备有限公司 | 护栏打桩机-打桩机厂家-恒新重工 | 高效复合碳源-多核碳源生产厂家-污水处理反硝化菌种一长隆科技库巴鲁 | 即用型透析袋,透析袋夹子,药敏纸片,L型涂布棒-上海桥星贸易有限公司 | 诚暄电子公司首页-线路板打样,pcb线路板打样加工制作厂家 | 交变/复合盐雾试验箱-高低温冲击试验箱_安奈设备产品供应杭州/江苏南京/安徽马鞍山合肥等全国各地 | 深圳成考网-深圳成人高考报名网 深圳工程师职称评定条件及流程_深圳职称评审_职称评审-职称网 | 双工位钻铣攻牙机-转换工作台钻攻中心-钻铣攻牙机一体机-浙江利硕自动化设备有限公司 | 粉末冶金注射成型厂家|MIM厂家|粉末冶金齿轮|MIM零件-深圳市新泰兴精密科技 | 无负压供水设备,消防稳压供水设备-淄博创辉供水设备有限公司 | 贴片电感_贴片功率电感_贴片绕线电感_深圳市百斯特电子有限公司 贴片电容代理-三星电容-村田电容-风华电容-国巨电容-深圳市昂洋科技有限公司 | 玉米深加工机械,玉米加工设备,玉米加工机械等玉米深加工设备制造商-河南成立粮油机械有限公司 | 车充外壳,车载充电器外壳,车载点烟器外壳,点烟器连接头,旅行充充电器外壳,手机充电器外壳,深圳市华科达塑胶五金有限公司 | 钢结构-钢结构厂房-钢结构工程[江苏海逵钢构厂] | 青州开防盗门锁-配汽车芯片钥匙-保险箱钥匙-吉祥修锁店 | 旋转滴界面张力仪(张力测定仪器)-百科| 鄂泉泵业官网|(杭州、上海、全国畅销)大流量防汛排涝泵-LW立式排污泵 |