Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationEventAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
3
Help us understand the problem. What is going on with this article?
@Enchan

【Python】ファイルをオンメモリで生成してFTPで転送する

FTP(SFTP)による高頻度なファイル転送を実装する機会があったので、
備忘録も兼ねてまとめました。

PythonでのFTP

PythonにはFTP周りのインタフェースを提供するライブラリftplibがあり、
これを用いることでFTPサーバとの通信プログラムを簡単に実装することができます。

ローカルファイルを転送する場合はこんな感じ:

ftptransfer.py
from ftplib import FTP

def main():
    # 接続
    ftp = FTP("example.com", "username", passwd = "password")

    # FTP.storlinesにファイルオブジェクトを渡す
    with open("test.txt", "rb") as f:
        ftp.storlines("STOR ./test.txt", f)

    # 切断
    ftp.quit()

if __name__ == "__main__":
    main()

しかし、この方法ではプログラム実行中に出力されたメモリ上のデータを転送することができません。
いちいちファイルに出力するのは冗長ですし、何よりストレージへの負荷がすごそうです。

オンメモリでファイルオブジェクトを作る

そこで、StringIOおよびBytesIOを用いてストリームを生成し、ftplibに渡す方法を考えます。

引用: Pythonドキュメント 「io --- ストリームを扱うコアツール

インメモリー ストリーム

str や bytes-like オブジェクト を、読み書き可能なファイルのように扱うことができます。 StringIO は文字列に対して、テキストモードで開かれたファイルのように使うことができます。 BytesIO はバイナリーモードで開いたファイルのように扱うことができます。この2つのクラスは、読み書き可能で、ランダムアクセス可能です。

storlinesはバイナリモードで開いたファイルのオブジェクトを渡す必要があるので、今回はio.BytesIOを使用します。

BytesIOTest.py
import io

def main():
    # io.BytesIOオブジェクトを生成
    bytesIO = io.BytesIO(bytes("Hello, World!!", encoding="utf-8"))
    print(type(bytesIO))

    # ファイルオブジェクトのように操作する
    with bytesIO as b:
        print(b.readlines())

if __name__ == "__main__":
    main()

# 実行結果
# <class '_io.BytesIO'>
# [b'Hello, World!!']

BytesIOオブジェクトが生成され、with文で読むとbytesが返ってきます。

ftplibに渡して転送する

では、このBytesIOオブジェクトをstorlinesに渡してみます。

sendOnMemoryFile.py
import io
from ftplib import FTP

def main():
    # io.BytesIOでファイルっぽいものを作り、
    bytesIO = io.BytesIO(bytes("Hello, World!!", encoding="utf-8"))
    print(type(bytesIO))

    # FTP.storlinesに渡して転送する
    ftp = FTP("example.com", "username", passwd = "password")
    ftp.storlines("STOR ./test.txt", bytesIO)

    ftp.quit()

if __name__ == "__main__":
    main()

実行後、サーバをのぞくと…

[username@example.com ~]$ cat test.txt 
Hello, World!!

記述した文字列が書き込まれたファイルtest.txtが作成されていることがわかります。

まとめ

ここまで読んでいただきありがとうございました。

まとめで言うのもアレですが、こんな面倒なことをするよりHTTPSを使うべきだと思います。
FTPはFile Transfer Protocolなので。

ではまた!

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
3
Help us understand the problem. What is going on with this article?