2010-08-10 45 views
0

我有下面的代码:如何使用Twisted通过FTP下载文件时关闭文件对象?

for f in fileListProtocol.files: 
    if f['filetype'] == '-': 
     filename = os.path.join(directory['filename'], f['filename']) 
     print 'Downloading %s...' % (filename) 
     newFile = open(filename, 'w+') 
     d = ftpClient.retrieveFile(filename, FileConsumer(newFile)) 
     d.addCallback(closeFile, newFile) 

不幸的是,下载的文件1000+数百在有关目录之后,我得到一个IOError约太多打开的文件。为什么当我在下载完成后关闭每个文件?如果有更习惯的方式来处理下载大量文件的整个任务,我很乐意听到它。谢谢。

更新:让 - 保罗的DeferredSemaphore例子加马特的FTPFile做了伎俩。出于某种原因,使用Cooperator而不是DeferredSemaphore会下载几个文件,然后失败,因为FTP连接已经死亡。

+0

“FTPClient”序列化命令,你不应该需要JP的并行化技术。问题在于你的FileConsumer在实例化时处理文件句柄,并且当下载完成时他们没有关闭文件,我期望你的'd.addCallback(closeFile,newFile)'不能按预期工作。我提供的类仅在需要时打开文件,并在完成时关闭它,因为它以'retrieveFile'预期的方式支持协议接口。 – MattH 2010-08-11 13:36:43

+0

好的,很酷。谢谢,马特。 – pr1001 2010-08-11 14:46:17

回答

1

假设你正在使用FTPClienttwisted.protocols.ftp ......我矛盾JP之前肯定毫不犹豫..

看来,FileConsumer类你传递给retrieveFiletwisted.internet.protocol.ConsumerToProtocolAdapter,适应IProtocol哪些不叫unregisterProducer,所以FileConsumer不关闭文件对象。

我敲了一个可以用来接收文件的快速协议。我认为它应该只在适当的时候打开文件。完全未经测试,您将在上面的代码中使用它来代替FileConsumer,并且不需要addCallback

from twisted.python import log 
from twisted.internet import interfaces 
from zope.interface import implements 

class FTPFile(object): 
    """ 
    A consumer for FTP input that writes data to a file. 

    @ivar filename: a filename to be opened for writing. 
    """ 

    implements(interfaces.IProtocol) 

    def __init__(self, filename): 
     self.fObj = None 
     self.filename = filename 

    def makeConnection(self,transport) 
     self.fObj = open(self.filename,'wb') 
     log.info('Opened %s for writing' % self.filename) 

    def connectionLost(self,reason): 
     self.fObj.close() 
     log.info('Closed %s' % self.filename) 

    def dataReceived(self, bytes): 
     self.fObj.write(bytes) 
+0

我在这里看不到矛盾。 :)如果'FTPClient'已经序列化操作,那么及时打开这些文件是有意义的。如果你连接到许多不同的FTP服务器,你仍然需要小心(或者即使你打开许多不同的连接到单个FTP服务器)。 – 2010-08-10 16:29:38

1

您正在同时打开fileListProtocol.files中的每个文件,将内容下载到它们,然后在每次下载完成时关闭每个文件。因此,您在进程开始时打开了len(fileListProtocol.files)文件。如果列表中的文件太多,那么您将尝试打开太多文件。

您可能希望一次只限于少量的并行下载(如果FTP甚至支持并行下载,我并不完全确定是这种情况)。

http://jcalderone.livejournal.com/24285.htmlQueue remote calls to a Python Twisted perspective broker?可能有助于找出如何限制并行启动的下载数量。

+0

从看看'FTPClientBasic',我的印象是它排队命令。 – MattH 2010-08-10 15:17:50

+0

我不知道我打开每个文件,但现在我认为这是有道理的。当然,我只想打开几个。我会研究你的链接。 – pr1001 2010-08-10 16:10:11

+0

让 - 保罗,我试着使用你的合作者代码,这看起来像我需要的,但不幸的是得到了完全相同的问题。你会说''parallel'中的'工作'迭代器是同时打开所有文件吗?我还需要Matt的代码吗? – pr1001 2010-08-11 09:44:59