2016-04-29 10 views
3

スタックオーバーフローについては、FTPファイルを取得し、それをストリングバッファやファイルなどのストリームに書き込んだり、反復処理を行うことができます。Python FTP "チャンク"イテレータ(ファイル全体をメモリにロードせずに)

のような:Read a file in buffer from FTP python

しかし、これらのソリューションは、ファイル全体をメモリにロードするか、内容を処理するために開始する前に、それをディスクにダウンロードすることを含みます。

ファイル全体をバッファリングするのに十分なメモリがないため、ディスクにアクセスできません。これはコールバック関数のデータを処理することで行うことができますが、私は、コードをでラップすることが可能かどうかを知りたいのですが、コールバックで自分のコードを処理するのではなく、イテレータを返します。

I.E.いうより:

def get_ftp_data(handle_chunk): 
    ... 
    ftp.login('uesr', 'password') # authentication required 
    ftp.retrbinary('RETR etc', handle_chunk) 
    ... 

get_ftp_data(do_stuff_to_chunk) 

私がしたい:(既存の答えとは違って)

for chunk in get_ftp_data(): 
    do_stuff_to_chunk(chunk) 

そして、私はそれを反復する前に、ディスクやメモリに全体のFTPファイルを記述することなく、それをやりたいです。

+1

同様の問題がある(http://stackoverflow.com/questions/9968592/turn-functions-with-a-callback-into- [Pythonのジェネレータへのコールバックで機能をオンにしますか?] python-generators) –

答えて

4

あなたは別のスレッドでretrbinaryコールを入れて、イテレータへのコールバックフィードブロックを持っている必要があります:

import threading, Queue 

def ftp_chunk_iterator(FTP, command): 
    # Set maxsize to limit the number of chunks kept in memory at once. 
    queue = Queue.Queue(maxsize=some_appropriate_size) 

    def ftp_thread_target(): 
     FTP.retrbinary(command, callback=queue.put) 
     queue.put(None) 

    ftp_thread = threading.Thread(target=ftp_thread_target) 
    ftp_thread.start() 

    while True: 
     chunk = queue.get() 
     if chunk is not None: 
      yield chunk 
     else: 
      return 

あなたがスレッドを使用することができない場合は、あなたができる最善のは、あなたのコールバックを書いていますコルーチンとして:

from contextlib import closing 


def process_chunks(): 
    while True: 
     try: 
      chunk = yield 
     except GeneratorExit: 
      finish_up() 
      return 
     else: 
      do_whatever_with(chunk) 

with closing(process_chunks()) as coroutine: 

    # Get the coroutine to the first yield 
    coroutine.next() 

    FTP.retrbinary(command, callback=coroutine.send) 
# coroutine.close() # called by exiting the block 
+0

私はそれを恐れていました。直感的には、スレッドを絶対に必要とするようなものではありません。また、私はこれを元の質問に明示していませんが、私の実行環境にはスレッドがありません。もっと良い方法があることを願っています。 – natb1

+0

@ natb1:残念ながら、スレッドが必要です。スレッドを使用できない場合は、コールバックをコルーチンとして記述することができます。これは柔軟性が低く、さらに混乱します。 – user2357112

+0

私をコルーチンに紹介してくれてありがとう。残念なことに、この例は私に、 'FTP.retrbinary(command、callback = do_whatever_with)'と言った長い風に見えます。 – natb1

関連する問題