Как закрыть файловые объекты при загрузке файлов через FTP с использованием Twisted? - PullRequest
0 голосов
/ 10 августа 2010

У меня есть следующий код:

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 прервется.

Ответы [ 2 ]

1 голос
/ 10 августа 2010

Предполагая, что вы используете FTPClient из twisted.protocols.ftp ... и я определенно сомневаюсь, прежде чем противоречить JP ..

Похоже, что класс FileConsumer вы переходите на retrieveFileбудет адаптирован к IProtocol на twisted.internet.protocol.ConsumerToProtocolAdapter, что не вызывает 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)
1 голос
/ 10 августа 2010

Вы открываете каждый файл в fileListProtocol.files одновременно, загружаете в них содержимое, а затем закрываете каждый после завершения каждой загрузки.Итак, у вас есть len(fileListProtocol.files) файлы, открытые в начале процесса.Если в этом списке слишком много файлов, вы попытаетесь открыть слишком много файлов.

Возможно, вы захотите ограничить себя довольно небольшим количеством параллельных загрузок одновременно (если FTP даже поддерживает параллельные загрузки)(но я не совсем уверен, что это так).

http://jcalderone.livejournal.com/24285.html и Очередь удаленных вызовов в перспективный брокер Python Twisted? может помочь в выяснениикак ограничить количество скачиваний, которые вы запускаете параллельно.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...