【问题标题】:Resumable file upload in pythonpython中的可恢复文件上传
【发布时间】:2017-02-03 07:51:06
【问题描述】:

我正在尝试在 python 中上传文件,我想以可恢复模式上传文件,即当互联网连接恢复时,文件上传从上一阶段恢复。

是否有任何支持可恢复文件上传的特定协议。

提前致谢

【问题讨论】:

标签: python python-2.7 resume-upload


【解决方案1】:

所以你需要寻找文件并发送一个 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 作为参数传递。 rest 通常是一个字节偏移量 请求的文件,告诉服务器重新开始发送文件的字节 在请求的偏移量处,跳过初始字节。但是请注意 RFC 959 只要求其余是包含字符的字符串 在 ASCII 码 33 到 ASCII 码 126 的可打印范围内。 因此,transfercmd() 方法将 rest 转换为字符串,但没有 检查字符串的内容。如果服务器没有 识别 REST 命令,将引发 error_reply 异常。 如果发生这种情况,只需调用 transfercmd() 而不使用 rest 参数

Source
还有一些代码taken from here

【讨论】:

    【解决方案2】:

    GuySoft 的出色回答 - 它对我帮助很大。我不得不稍微修改它,因为我(到目前为止)从未遇到过他的脚本捕获的三个异常,但是我在 FTP 上传时遇到了很多 ConnectionResetError 和 socket.timeout 错误,所以我添加了它。我还注意到,如果我在 ftp 登录时添加 60 秒的超时,ConnectionResetErrors 的数量会显着下降(但不是全部一起)。经常发生上传经常在 ftp.storbinary 卡在 100% 直到 socket.timeout,然后尝试 49 次并退出。我通过比较 totalSize 和 rest_pos 来解决这个问题,并在相等时退出。 所以我现在有工作解决方案,但我会尝试找出导致套接字超时的原因。 有趣的是,当我使用 Filezilla 甚至 PHP 脚本时,上传到同一 FTP 服务器的文件正常工作。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-06-14
      • 2011-10-14
      • 1970-01-01
      • 1970-01-01
      • 2018-08-17
      • 2021-12-06
      • 2023-03-07
      • 2019-04-11
      相关资源
      最近更新 更多