2010-08-10 43 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