Python Ftp 文件、文件夾上傳下載操作

Python3 通過FTP 文件、文件夾上傳因痛、下載

# -*- encoding: utf-8 -*-
"""
@Project :   app
@File    :   ftpHelper.py
@Contact :   networkaccounts@163.com
@Modify Time :  2020-08-26 15:46
@Author  :  Joker
@Version : 1.0
@Description : None

# 設(shè)置FTP當(dāng)前操作的路徑,同linux中的cd
ftp.cwd(path)

# 顯示目錄下所有信息
ftp.dir()

# 獲取目錄下的文件岸更,顯示的是文件名列表
ftp.nlst()

# 新建遠(yuǎn)程目錄
ftp.mkd(directory)

# 刪除遠(yuǎn)程目錄
ftp.rmd(directory)

# 將遠(yuǎn)程文件old重命名為new
ftp.rename(old, new)

# 刪除遠(yuǎn)程文件
ftp.delete(file_name)

# 上傳文件鸵膏,cmd是一個(gè)存儲(chǔ)命令,可以為"STOR filename.txt"怎炊, fp為類文件對(duì)象(有read方法)谭企,bufsize設(shè)置緩沖大小
ftp.storbinary(cmd, fp, bufsize)

# 下載文件,cmd是一個(gè)獲取命令评肆,可以為"RETR filename.txt"债查, callback是一個(gè)回調(diào)函數(shù),用于讀取獲取到的數(shù)據(jù)塊
ftp.retrbinary(cmd, callback, bufsize)
"""
from ftplib import FTP, error_perm
import os


class ftpHelper(object):
    conn = FTP()

    def __init__(self, host, port=21):
        """
        創(chuàng)建連接
        :param host:
        :param port:
        """
        self.conn.connect(host, port)

    def login(self, username, password):
        """
        登錄
        :param username:
        :param password:
        :return:
        """
        self.conn.login(username, password)
        self.conn.encoding = "GB2312"
        # 打開調(diào)試級(jí)別2瓜挽,顯示詳細(xì)信息
        self.conn.set_debuglevel(2)
        self.conn.set_pasv(True)
        # 0 主動(dòng)模式 1 #被動(dòng)模式
        print(self.conn.welcome)

    def _ftp_list(self, line):
        li = line.split(' ')
        if self.ftp_dir_name == li[-1] and "<DIR>" in li:
            self._is_dir = True

    def _is_ftp_file(self, ftp_path):
        try:
            if ftp_path in self.conn.nlst(os.path.dirname(ftp_path)):
                return True
            else:
                return False
        except error_perm as e:
            return False

    def _is_ftp_dir(self, ftp_path):
        """
        用來判斷所給的路徑是文件還是文件夾
        """
        ftp_path = ftp_path.rstrip('/')
        ftp_parent_path = os.path.dirname(ftp_path)
        self.ftp_dir_name = os.path.basename(ftp_path)
        self._is_dir = False
        if ftp_path == '.' or ftp_path == './' or ftp_path == '':
            self._is_dir = True
        else:
            try:
                self.conn.cwd(ftp_path)
                self._is_dir = True
                # self.conn.retrlines('LIST %s' %ftp_parent_path,self._ftp_list)
            except error_perm as e:
                return self._is_dir
        return self._is_dir

    def get_file(self, ftp_path="", local_path="."):
        """
        下載文件
        :param ftp_path:
        :param local_path:
        :return:
        """
        print(ftp_path)
        ftp_path = ftp_path.rstrip('/')

        file_name = os.path.basename(ftp_path)

        # 如果本地路徑是目錄盹廷,下載文件到該目錄
        if os.path.isdir(local_path):
            file_handler = open(os.path.join(local_path, file_name), 'wb')
            self.conn.retrbinary("RETR %s" % ftp_path, file_handler.write)
            file_handler.close()

        # 如果本地路徑不是目錄,但上層目錄存在久橙,則按照本地路徑的文件名作為下載的文件名稱
        elif os.path.isdir(os.path.dirname(local_path)):
            file_handler = open(local_path, 'wb')
            self.conn.retrbinary("RETR %s" % ftp_path, file_handler.write)
            file_handler.close()
        # 如果本地路徑不是目錄俄占,且上層目錄不存在,則退出
        else:
            print('EROOR:The dir:%s is not exist' % os.path.dirname(local_path))

    def get_dir(self, ftp_path, local_path=".", begin=True):
        """
        下載目錄下的所有文件
        :param ftp_path:
        :param local_path:
        :param begin:
        :return:
        """
        if not self._is_ftp_dir(ftp_path):
            self.get_file(ftp_path=ftp_path, local_path=local_path)
            return

        if begin:
            local_path = os.path.join(local_path, os.path.basename(ftp_path))

        # 如果本地目錄不存在淆衷,則創(chuàng)建目錄
        if not os.path.isdir(local_path):
            os.mkdir(local_path)

        # 進(jìn)入ftp目錄缸榄,開始遞歸查詢
        self.conn.cwd(ftp_path)

        ftp_files = self.conn.nlst()

        for file in ftp_files:
            local_file = os.path.join(local_path, file)
            # 如果file ftp路徑是目錄則遞歸上傳目錄(不需要再進(jìn)行初始化begin的標(biāo)志修改為False)
            # 如果file ftp路徑是文件則直接上傳文件
            if self._is_ftp_dir(file):
                self.get_dir(file, local_file, False)
            elif "idea" in file:
                pass
            else:
                self.get_file(ftp_path=file, local_path=local_file)

        # 如果當(dāng)前ftp目錄文件已經(jīng)遍歷完畢返回上一層目錄
        self.conn.cwd("..")

    def get_all_dir(self):
        ftp_files = self.conn.nlst()
        for file in ftp_files:
            self.get_dir(file, "D:\\ftp", True)

    def put_file(self, local_path, ftp_path="."):
        """
        上傳文件
        :param local_path:
        :param ftp_path:
        :return:
        """
        ftp_path = ftp_path.rstrip('/')
        if os.path.isfile(local_path):
            file_handler = open(local_path, 'rb')
            local_file_name = os.path.basename(local_path)

            # 如果遠(yuǎn)程路徑是個(gè)目錄,則上傳文件到這個(gè)目錄祝拯,文件名不變
            if self._is_ftp_dir(ftp_path):
                self.conn.storbinary('STOR %s' % os.path.join(ftp_path, local_file_name), file_handler)

            # 如果遠(yuǎn)程路徑的上層是個(gè)目錄甚带,則上傳文件,文件名按照給定命名
            elif self._is_ftp_dir(os.path.dirname(ftp_path)):
                print('STOP %s' % ftp_path)
                self.conn.storbinary('STOR %s' % ftp_path, file_handler)
            # 如果遠(yuǎn)程路徑不是目錄,且上一層的目錄也不存在鹰贵,則提示給定遠(yuǎn)程路徑錯(cuò)誤
            else:
                print('STOR %s' % ftp_path, file_handler)

    def put_dir(self, local_path, ftp_path=".", begin=True):
        """
        上傳文件夾
        :param local_path:
        :param ftp_path:
        :param begin:
        :return:
        """
        ftp_path = ftp_path.rstrip('/')

        if not os.path.isdir(local_path):
            print('ERROR:The dir:%s is not exist' % local_path)
            return

        # 當(dāng)本地目錄存在時(shí)上傳
        # 上傳初始化:如果給定的ftp路徑不存在需要?jiǎng)?chuàng)建晴氨,同時(shí)將本地的目錄存放在給定的ftp目錄下。
        # 本地目錄下文件存放的路徑為ftp_path = ftp_path + os.path.basename(local_path)
        # 例如碉输,將本地的文件夾a上傳到ftp的a/b目錄下瑞筐,則本地a目錄下的文件將上傳的ftp的a/b/a目錄下
        if begin:
            if not self._is_ftp_dir(ftp_path):
                try:
                    self.conn.mkd(ftp_path)
                except Exception as e:
                    print(e)
            ftp_path = os.path.join(ftp_path, os.path.basename(local_path))

        # 如果上傳路徑是文件夾,則創(chuàng)建目錄
        if not self._is_ftp_dir(ftp_path):
            try:
                self.conn.mkd(ftp_path)
            except Exception as e:
                print(e)

        # 進(jìn)入本地目錄腊瑟,開始遞歸查詢
        os.chdir(local_path)
        local_files = os.listdir('.')
        for file in local_files:
            ftp_file = os.path.join(ftp_path, file)
            # 如果file本地路徑是目錄則遞歸上傳文件(不需要再進(jìn)行初始化begin的標(biāo)志修改為False)
            # 如果file本地路徑是文件則直接上傳文件
            if os.path.isdir(file):
                self.put_dir(file, ftp_file, False)
            elif "idea" in file:
                pass
            else:
                self.put_file(file, ftp_path)

        # 如果當(dāng)前本地目錄文件已經(jīng)遍歷完畢返回上一層目錄
        os.chdir('..')


# todo
if __name__ == "__main__":
    # local = '/home/app/ftp.py'
    local = '/home/app'

    ftp = ftpHelper('192.168.43.26')
    ftp.login('test', "test")
    # ftp.get_file("ftppath")
    # ftp.get_dir("ftppath","localpath",True)
    # ftp.get_dir("","",True)
    # ftp.get_all_dir("")
    # ftp.put_file(local)
    ftp.put_dir(local, "/temp", begin=True)

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市块蚌,隨后出現(xiàn)的幾起案子闰非,更是在濱河造成了極大的恐慌,老刑警劉巖峭范,帶你破解...
    沈念sama閱讀 219,589評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件财松,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡纱控,警方通過查閱死者的電腦和手機(jī)辆毡,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,615評(píng)論 3 396
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來甜害,“玉大人舶掖,你說我怎么就攤上這事《辏” “怎么了眨攘?”我有些...
    開封第一講書人閱讀 165,933評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)嚣州。 經(jīng)常有香客問我鲫售,道長(zhǎng),這世上最難降的妖魔是什么该肴? 我笑而不...
    開封第一講書人閱讀 58,976評(píng)論 1 295
  • 正文 為了忘掉前任情竹,我火速辦了婚禮,結(jié)果婚禮上匀哄,老公的妹妹穿的比我還像新娘秦效。我一直安慰自己,他們只是感情好涎嚼,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,999評(píng)論 6 393
  • 文/花漫 我一把揭開白布棉安。 她就那樣靜靜地躺著,像睡著了一般铸抑。 火紅的嫁衣襯著肌膚如雪贡耽。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,775評(píng)論 1 307
  • 那天,我揣著相機(jī)與錄音蒲赂,去河邊找鬼阱冶。 笑死,一個(gè)胖子當(dāng)著我的面吹牛滥嘴,可吹牛的內(nèi)容都是我干的木蹬。 我是一名探鬼主播,決...
    沈念sama閱讀 40,474評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼若皱,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼镊叁!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起走触,我...
    開封第一講書人閱讀 39,359評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤晦譬,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后互广,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體敛腌,經(jīng)...
    沈念sama閱讀 45,854評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,007評(píng)論 3 338
  • 正文 我和宋清朗相戀三年惫皱,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了像樊。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,146評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡旅敷,死狀恐怖生棍,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情媳谁,我是刑警寧澤足绅,帶...
    沈念sama閱讀 35,826評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站韩脑,受9級(jí)特大地震影響氢妈,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜段多,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,484評(píng)論 3 331
  • 文/蒙蒙 一首量、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧进苍,春花似錦加缘、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,029評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至杠人,卻和暖如春勋乾,著一層夾襖步出監(jiān)牢的瞬間宋下,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,153評(píng)論 1 272
  • 我被黑心中介騙來泰國(guó)打工辑莫, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留学歧,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,420評(píng)論 3 373
  • 正文 我出身青樓各吨,卻偏偏與公主長(zhǎng)得像枝笨,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子揭蜒,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,107評(píng)論 2 356

推薦閱讀更多精彩內(nèi)容