Возобновляемая загрузка файлов в python

Я пытаюсь загрузить файл в python, и я хочу загрузить файл в возобновляемом режиме, т.е. когда возобновляется подключение к Интернету, возобновляется загрузка файла с предыдущего этапа.

Есть ли какой-то конкретный протокол, который поддерживает возобновляемую загрузку файлов.

заранее спасибо

2 ответа

Поэтому вам нужно найти файл и отправить команду REST, чтобы сообщить серверу о загрузке из нужного места.

Вот код, который будет пытаться до тех пор, пока он не завершит загрузку с резюме, также включена отладка, чтобы вы могли следовать:

#!/usr/bin/env python3
import ftplib
import os
import sys
import time
import socket

class FtpUploadTracker:
    sizeWritten = 0
    totalSize = 0.0
    lastShownPercent = 0

    def __init__(self, totalSize):
        self.totalSize = totalSize

    def handle(self, block):
        self.sizeWritten += 1024
        percentComplete = round((self.sizeWritten / self.totalSize) * 100)

        if (self.lastShownPercent != percentComplete):
            self.lastShownPercent = percentComplete
            print(str(percentComplete) + "% complete ramaing: " + str(self.totalSize - self.sizeWritten), flush=True)



if __name__ == "__main__":
    Server="servername.com"
    Username="username"
    Password="secret password"
    filename = "/path/to/folder"
    Directory="/path/on/server"

    tries = 0
    done = False

    print("Uploading " + str(filename) + " to " + str(Directory), flush=True)

    while tries < 50 and not done:
        try:
            tries += 1
            with ftplib.FTP(Server) as ftp:
                ftp.set_debuglevel(2)
                print("login", flush=True)
                ftp.login(Username, Password)
                # ftp.set_pasv(False)
                ftp.cwd(Directory)
                with open(filename, 'rb') as f:
                    totalSize = os.path.getsize(filename)
                    print('Total file size : ' + str(round(totalSize / 1024 / 1024 ,1)) + ' Mb', flush=True)
                    uploadTracker = FtpUploadTracker(int(totalSize))

                    # Get file size if exists
                    files_list = ftp.nlst()
                    print(files_list, flush=True)
                    if os.path.basename(filename) in files_list:
                        print("Resuming", flush=True)
                        ftp.voidcmd('TYPE I')
                        rest_pos = ftp.size(os.path.basename(filename))
                        f.seek(rest_pos, 0)
                        print("seek to " + str(rest_pos))
                        uploadTracker.sizeWritten = rest_pos
                        print(ftp.storbinary('STOR ' + os.path.basename(filename), f, blocksize=1024, callback=uploadTracker.handle, rest=rest_pos), flush=True)
                    else:
                        print(ftp.storbinary('STOR ' + os.path.basename(filename), f, 1024, uploadTracker.handle), flush=True)
                        done = True

        except (BrokenPipeError, ftplib.error_temp, socket.gaierror) as e:
            print(str(type(e)) + ": " + str(e))
            print("connection died, trying again")
            time.sleep(30)


    print("Done")

Волшебная линия:

print(ftp.storbinary('STOR ' + os.path.basename(filename), f, blocksize=1024, callback=uploadTracker.handle, rest=rest_pos), flush=True)

У которого есть rest=rest_pos,

Если задан необязательный отдых, команда REST отправляется на сервер, передавая rest в качестве аргумента. rest - это обычно смещение байта в запрошенном файле, указывающее серверу перезапустить передачу байтов файла с запрошенным смещением, пропуская начальные байты. Однако обратите внимание, что RFC 959 требует только, чтобы rest был строкой, содержащей символы в печатаемом диапазоне от ASCII-кода 33 до ASCII-кода 126. Поэтому метод Transfercmd() конвертирует rest в строку, но проверка содержимого строки не выполняется., Если сервер не распознает команду REST, будет сгенерировано исключение error_reply. Если это произойдет, просто вызовите Transfercmd() без аргумента rest

Источник
Также некоторый код взят здесь

Отличный ответ от GuySoft - мне очень помогло. Мне пришлось немного изменить его, поскольку я никогда (пока) не сталкивался с тремя исключениями, которые улавливает его сценарий, но я испытал много ошибок ConnectionResetError и socket.timeout при загрузке по FTP, поэтому я добавил это. Я также заметил, что если я добавил тайм-аут 60 секунд при входе в систему по ftp, количество ConnectionResetErrors значительно уменьшилось (но не все вместе). Часто происходило то, что загрузка зависала на 100% на ftp.storbinary до socket.timeout, затем пыталась 49 раз и выходила. Я исправил это, сравнив totalSize и rest_pos, и вышел при равенстве. Итак, у меня есть рабочее решение, но я попытаюсь выяснить, что вызывает тайм-ауты сокета. Интересно то, что когда я использовал Filezilla и даже скрипт PHP, загрузка файлов на один и тот же FTP-сервер работала без сбоев.

Другие вопросы по тегам