Я пытаюсь загрузить nr blastdabase с ftp-сайта NCBI (ftp: // ftp. ncbi.nlm.nih.gov/blast/db). Один из файлов довольно большой (16 ГБ), и его загрузка занимает некоторое время. По окончании загрузки этого файла программа просто зависает, не переходит к следующему файлу.
Часть моей программы, связанная с загрузкой файлов:
from pathlib import Path
import ftplib
from tqdm import tqdm
def _file_write_progress(block, fh, pbar):
"""Write ftp file and updates progress bar.
Args:
block (binary): Block of data received from ftp.retrbinary
fh (BufferedWriter): Open file to write to in wb mode
pbar (ProgressBar): Progress bar to update with download progress
"""
fh.write(block)
pbar.update(len(block))
def _download_ftp_files(url, remote_path, files_list, db_dir):
"""Download ftp file and update progress bar.
Args:
url (str): Url of ftp server to connect to
remote_path (str): Path to directory containing tartget files
files_list (list(str)): List of files to download
db_dir (Path): Path to local directory to download files to
"""
ftp = ftplib.FTP(url, timeout=3600)
ftp.login()
ftp.cwd(remote_path)
for fn in tqdm(files_list, desc="Downloading file #"):
with (db_dir / fn).open('wb') as fh:
pbar = tqdm(desc=fn, total=ftp.size(fn))
ftp.retrbinary(
'RETR ' + fn,
lambda block: _file_write_progress(block, fh, pbar),
1024*1024
)
ftp.close()
Я думаю, что проблема связана с тайм-аутом ftp-соединения, но я не могу это исправить.
Я пробовал решения на Python: ftplib зависает в конце передачи и Python: загрузка файла использование ftplib зависает навсегда после успешной загрузки файла, но, похоже, это не работает.
Приведенный выше код изменен на основе этих ответов:
def _background(sock, fh, pbar):
while True:
block = sock.recv(1024*1024)
if not block:
break
fh.write(block)
pbar.update(len(block))
def _download_ftp_files(url, remote_path, files_list, db_dir):
ftp = ftplib.FTP(url)
ftp.login()
ftp.cwd(remote_path)
for fn in tqdm(files_list, desc="Downloading file #"):
try:
sock, size = ftp.ntransfercmd('RETR ' + fn)
pbar = tqdm(desc=fn, total=size)
with (db_dir / fn).open('wb') as fh:
t = threading.Thread(target=_background(sock, fh, pbar))
t.start()
while t.is_alive():
t.join(60)
ftp.voidcmd('NOOP')
sock.close()
except ftplib.error_reply as e:
print(e)
По какой-то причине это возвращает ftplib.error_reply 226 Transfer Completed в качестве исключения. Пытаюсь справиться, но программа просто зависает.
При необходимости я могу предоставить дополнительную информацию, любая помощь приветствуется!