进程函数通常使用pycurl进行FTP上传

时间:2014-07-21 21:59:19

标签: python upload ftp progress pycurl

我在Ubuntu 12.0.4上使用pycurl版本7.19和libcurl3版本7.22(pycurl和libcurl都直接从Ubuntu存储库安装apt-get)。我上传文件的代码是(“self”是我的包装对象):

self.curlTransfer = pycurl.Curl()
self.curlTransfer.setopt(pycurl.UPLOAD, 1)
self.curlTransfer.setopt(pycurl.USERPWD, '%s:%s'%(str(self.userName), str(self.password)))
self.curlTransfer.setopt(pycurl.NOPROGRESS, 0)
self.curlTransfer.setopt(pycurl.PROGRESSFUNCTION, self.__UpdateFileTransferProgress)
f = open(fileName, 'rb')
self.curlTransfer.setopt(pycurl.URL, 'ftp://' + self.ipAddress + self.path + destination)
self.curlTransfer.setopt(pycurl.INFILESIZE_LARGE, os.path.getsize(fileName))
self.curlTransfer.setopt(pycurl.READFUNCTION, f.read)
self.curlTransfer.perform()

我的回调函数“__UpdateFileTransferProgress”每秒被调用数千次到传输比我关闭进程回调慢约3倍的点。我已经进行了广泛的搜索以解决这个问题,我发现的唯一相关内容是this curl bug report。听起来这个bug可能已被修补,但是不清楚补丁是否已经进入我的版本(或者这完全是另一个问题)。

有没有人碰到过这个?我考虑手动更新到最新的libcurl / pycurl版本,但是试图通过依赖项来阻止我。我非常喜欢pycurl与ftplib相比的性能(当禁用进程回调时),但是我需要回调函数来跟踪传输进度。

1 个答案:

答案 0 :(得分:1)

请参阅清洁解决方案编辑!

我点了一下子弹并下载了libcurl和pycurl的最新源代码(实际上很容易构建/安装)。这改善了这种情况,因为进度函数现在每秒只调用数百次而不是数千次,但在使用进度回调时仍然会有非常明显的性能损失。为了避免这种情况,我设置了这样的转移:

# Set transfer parameters.
self.curlTransfer.fp = open(fileName, 'rb')
self.curlTransfer.fileSize = os.path.getsize(fileName)
self.curlTransfer.setopt(pycurl.URL, 'ftp://' + self.ipAddress + self.path + destination)
self.curlTransfer.setopt(pycurl.INFILESIZE_LARGE, self.curlTransfer.fileSize)
self.curlTransfer.setopt(pycurl.READDATA, self.curlTransfer.fp)

# Store file.
self.curlTransfer.perform()

然后如果我想在另一个线程中获得进展:

def GetDataTransferred(self):
"""
Gets the amount of data transferred for the current file transfer.

@return Amount of data transferred (MB).
"""
try:

    # Try/except in case file is closed.
    try:
        return (float(self.curlTransfer.fp.tell())/float(myConstants.MB))
    except:
        if(self.curlTransfer.fileSize):
            return self.curlTransfer.fileSize

    return 0

except:
    Warning("Unable to get the amount of data transferred.")
    return 0

基本上我作弊并使用文件指针“tell”来查看pycurl在传输中的位置。

编辑/解决:我最后通过修改/lib/progress.c修复了libcurl中的错误,如我的OP(Imgur link)中的错误报告线程所示。听起来他们在他们的主干源代码中提交了修复程序,但它没有包含在他们的最新版本中(7.37.1)。我最终走这条路的原因是因为最简单的停止转移的方法是从进度函数返回非零值。您可以从pycurl.READFUNCTION返回非零值以停止传输,但是使用FTP上传时,每个块(~16KB)调用该函数一次并且非常慢(使用pycurl.READDATA代替并提供文件指针)。现在我可以干净地停止传输,使用他们预期的进度更新方法,并保持libcurl的高性能。