我正在尝试上传 python 中的文件,我想以可恢复模式上传文件,即当互联网连接恢复时,文件上传从前一阶段恢复。
是否有支持可恢复文件上传的特定协议。
提前致谢
答案 0 :(得分: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通常是一个字节偏移到 请求文件,告诉服务器重新开始发送文件的字节 在请求的偏移处,跳过初始字节。但请注意 RFC 959只要求rest是一个包含字符的字符串 在从ASCII码33到ASCII码126的可打印范围内 因此,transfercmd()方法将rest转换为字符串,但不是 检查是否对字符串的内容执行。如果服务器没有 识别REST命令,将引发error_reply异常。 如果发生这种情况,只需调用transfercmd()而不使用rest参数
Source
还有一些代码taken from here
答案 1 :(得分:0)
GuySoft 的出色回答 - 对我帮助很大。我不得不稍微修改它,因为我从未(到目前为止)遇到他的脚本捕获的三个异常,但我在 FTP 上传时遇到了很多 ConnectionResetError 和 socket.timeout 错误,所以我添加了它。我还注意到,如果我在 ftp 登录时添加 60 秒的超时,ConnectionResetErrors 的数量会显着下降(但不是全部)。经常发生上传经常在 ftp.storbinary 卡在 100% 直到 socket.timeout,然后尝试 49 次并退出的情况。我通过比较 totalSize 和 rest_pos 解决了这个问题,并在相等时退出。 所以我现在有工作解决方案,但我会尝试找出导致套接字超时的原因。 有趣的是,当我使用 Filezilla 甚至是 PHP 脚本时,文件上传到同一个 FTP 服务器时没有出现故障。