2

I'm trying to download a file from FTP server which is about 100 MB. It's a test .bin file because I'm testing the app and I guess the files I will want to download in the future will weight even more. When I want to download the file the whole application just freezes and then after a few seconds it downloads the file. The file is complete and it downloads it successfully without any errors or something like that. The only problem is the freeze.

My code:

ftp = FTP('exampledomain.com')
ftp.login(user='user', passwd='password')

ftp.cwd('/main_directory/')

filename = '100MB.bin'

with open(filename, 'wb') as localfile:
    ftp.retrbinary('RETR ' + filename, localfile.write, 1024)

ftp.quit()
localfile.close()

I tried using sleep() between some lines of the code e.g between the logging in and downloading the file but it didn't help and it also seems that sleep() does not work AT ALL when working with FTP.

Martin Prikryl
  • 188,800
  • 56
  • 490
  • 992
Qiasm
  • 356
  • 6
  • 15
  • What do you mean by freeze? It's expected that if the file is being downloaded your scirpt will be blocked until the download is completed. Are you inside of a GUI that you need active while downloading? If so, then make the function async – R10t-- Aug 21 '19 at 22:07
  • @R10t-- I think I almost got it now here is my code: ```async def update_status(self): if connecting: await self.updateStatusText.setText("Status: Connecting...") elif downloading: await self.updateStatusText.setText("Status: Downloading...") elif downloaded: await self.updateStatusText.setText("Status: Updated!") ``` I get a TypeError: TypeError: object NoneType can't be used in 'await' expression. Do you know what causes this error? I can't figure it out. I've 'awaited' everything and I'm using asyncio. – Qiasm Aug 21 '19 at 23:00
  • it seems `setText()` returns `None` so you have `await None` – furas Aug 21 '19 at 23:45
  • 1
    `await` doesn't work with every function, it has to be [awaitable](https://docs.python.org/3/library/asyncio-task.html#awaitables) function. For example it will not work with standard `time.sleep()`, it needs special `asyncio.sleep()` – furas Aug 21 '19 at 23:52
  • Okay. Thanks for the help. Do you know how can I make it another way so it does not freeze? – Qiasm Aug 22 '19 at 01:00

1 Answers1

2

Download the file on another thread:

import threading
import time
from ftplib import FTP

def download():
    ftp = FTP('exampledomain.com')
    ftp.login(user='user', passwd='password')

    ftp.cwd('/main_directory/')

    filename = '100MB.bin'

    with open(filename, 'wb') as localfile:
        ftp.retrbinary('RETR ' + filename, localfile.write)

    ftp.quit()

print("Starting download...")

thread = threading.Thread(target=download)
thread.start()

print("Download started")

while thread.isAlive():
    print("Still downloading...")
    time.sleep(1)

print("Done")

Based on:
How to download a file over HTTP with multi-thread (asynchronous download) using Python 2.7

Your followup question about modifying the code for PyQt:
FTP download with text label showing the current status of the download

Martin Prikryl
  • 188,800
  • 56
  • 490
  • 992
  • Thanks. It's simple and I understand it and I guess it would work with prints but I'm actually using PyQt 4 and the FTP download is started by a button and I want to change the text label. I forgot to mention it. Do I have to rewrite the code in like a different way or in PyQt 4 GUIs I have to use QThread? – Qiasm Aug 22 '19 at 06:53
  • See [Updating GUI elements in MultiThreaded PyQT](https://stackoverflow.com/q/9957195/850848). – Martin Prikryl Aug 22 '19 at 06:56
  • I'm quite new in Python and even more new in PyQt. I quite don't understand it. How do I convert the code to download file instead of URLs like in the question you linked? – Qiasm Aug 22 '19 at 07:05
  • Well, I'm new to Python as well and I do not know anything about PyQt. But I believe it's rather obvious how to modify the code. Anyway, how do you *"want to change the text label"*? What do you want to show there? – Martin Prikryl Aug 22 '19 at 07:23
  • I want to show the status of the download e.g: "Connecting...", "Downloading..." – Qiasm Aug 22 '19 at 07:24
  • Well I modified the code but It doesn't work so I guess I'm doing something wrong. I posted the code to hastebin so It's easier to read: https://hastebin.com/wilitamiye.rb – Qiasm Aug 22 '19 at 07:29
  • I've moved the PyQt answer to your other question. – Martin Prikryl Aug 22 '19 at 07:37