見出し画像

【python3】ftplibを使ってFTP接続してファイルをアップロードする

これやって

こうしまして、今回は最後の仕上げのFTP接続してアップロードです。

とりあえず結論

class FtpAccount(Enum):
   ACCOUNT = "hoge"
   PASSWORD = "huga"
   HOST = "host"
   ROOT_FOLDER_NAME = "app-test"

こんな感じでアカウント情報クラスに接続情報押し込んでおいてー

import ftplib
from enum import Enum

class FtpClient():
   # FTPアカウントを渡してインスタンスを作る
   def __init__(self,ftp_account: FtpAccount) -> None:
       self.account = ftp_account.ACCOUNT.value
       self.password = ftp_account.PASSWORD.value
       self.host = ftp_account.HOST.value
       self.root_folder_name = ftp_account.ROOT_FOLDER_NAME.value
       self.ftp = None
   
   # ファイルオブジェクトとファイル名渡すと接続してアップロードする
   def upload(self, target_file, file_name):
       self.ftp = self.__connect()
       file_path = f"{self.root_folder_name}/{file_name}"

       try:
           self.ftp.storlines("STOR " + file_path, target_file)
           return(True)
       except:
           print("error dayo")
           return(False)
       finally:
           # 例外が起きても必ずself.__closeを呼べるようにする
           print("finally dayo")
           self.__close()

   # 接続する
   def __connect(self):
       print(f"{self.account}/{self.host}/{self.password}")
       try:
           ftp = ftplib.FTP(host = self.host)
           ftp.set_pasv(True)
           ftp.login(user = self.account,passwd=self.password)
           return(ftp)
       except:
           self.__close()
           return(None)
           
   # 接続を閉じる        
   def __close(self):
       if(self.ftp != None):
           self.ftp.close()

本体はこんな感じにつくってー

呼び出す時は

import io

ftp = FtpClient(FtpAccount)

file = ('hoge,huga\nname,0')
file_binary = file.encode("utf-8")
file_stream = io.BytesIO(file_binary)
file_name = "test_csv.csv"

ftp.upload(file_stream, file_name)

前回作った、メモリ上に一時ファイル作るクラスと組み合わせて使うつもりで作ったんで、テスト用にメモリ上に作った一時ファイル渡してますが、普通にfile.openで開いたファイルオブジェクト渡しても大丈夫です。

とりあえずこんな感じにリポジトリクラスを作成してみました。

何だったかの都合で、接続をwithで管理するのがハマらなかったので、一々tryを仕込んでfinally節で接続を閉じる処理を呼んでいます。withがハマるならwithで自動的に閉じるようにした方が安全だと思う。

FTP接続の基本的な手順

import ftplib

で標準モジュールのftplibをお呼び出しする

ftp = ftplib.FTP(host = self.host)
ftp.set_pasv(True)
ftp.login(user = self.account,passwd=self.password)

で、ホストとアカウントとパスワードを渡して接続(必要に応じてパッシブモードにする)

ftp.storlines("STOR " + file_path, target_file)

でファイルをアップロード

このとき、該当のフォルダが無いと処理がコケるので、該当フォルダが何かの拍子に消えてしまう可能性のある運用をしている場合はフォルダ作る処理を入れた方が良い。

おまけ:サーバー上のフォルダの有無確認して、なかったら作る

def check_folder(ftp):
   # ルートフォルダから親フォルダを探す
   filelist1 = ftp.nlst("/")
   check1 = UPLOAD_FOLDER_PEARENT in filelist1
   if(check1 == False):
       ftp.mkd(UPLOAD_FOLDER_PEARENT)
       print(UPLOAD_FOLDER_PEARENT + "フォルダを作成しました")
   
   # 親フォルダからアップロードしたいフォルダを探す
   filelist = ftp.nlst(UPLOAD_FOLDER_PEARENT)
   check = UPLOAD_FOLDER in filelist
   if(check == False):
       ftp.mkd(UPLOAD_FOLDER)
       print(UPLOAD_FOLDER + "フォルダを作成しました")

ちょっと昔に作った処理なので、そこメソッド分けた方がよくね?みたいな所あるけど目を瞑って貰いたい。

しかもこれは、ルートフォルダ>親フォルダ>アップロードしたいフォルダという構成になっている場合に、親フォルダごと消えてるー!!って事件が発生したときに作った回避用なので二段構えになってる。そんな込み入ったところにアップするんでなければ一段構えで大丈夫。

この記事が気に入ったらサポートをしてみませんか?