python ftplib模塊使用


Python中默認安裝的ftplib模塊定義了FTP類,可用來實現簡單的ftp客戶端,用於上傳或下載文件。

ftplib模塊常用方法

ftp登陸連接
from ftplib import FTP            #加載ftp模塊
ftp=FTP()                         #設置變量
ftp.set_debuglevel(2)             #打開調試級別2,顯示詳細信息
ftp.connect("IP","port")          #連接的ftp sever和端口
ftp.login("user","password")      #連接的用戶名,密碼
print ftp.getwelcome()            #打印出歡迎信息
ftp.cmd("xxx/xxx")                #進入遠程目錄
bufsize=1024                      #設置的緩沖區大小
filename="filename.txt"           #需要下載的文件
file_handle=open(filename,"wb").write #以寫模式在本地打開文件
ftp.retrbinaly("RETR filename.txt",file_handle,bufsize) #接收服務器上文件並寫入本地文件
ftp.set_debuglevel(0)             #關閉調試模式
ftp.quit()                        #退出ftp
 
ftp相關命令操作
ftp.cwd(pathname)                 #設置FTP當前操作的路徑
ftp.dir()                         #顯示目錄下所有目錄信息
ftp.nlst()                        #獲取目錄下的文件
ftp.mkd(pathname)                 #新建遠程目錄
ftp.pwd()                         #返回當前所在位置
ftp.rmd(dirname)                  #刪除遠程目錄
ftp.delete(filename)              #刪除遠程文件
ftp.rename(fromname, toname)#將fromname修改名稱為toname。
ftp.storbinaly("STOR filename.txt",file_handel,bufsize)  #上傳目標文件
ftp.retrbinary("RETR filename.txt",file_handel,bufsize)  #下載FTP文件

FTP.quit()與FTP.close()的區別

  • FTP.quit():發送QUIT命令給服務器並關閉掉連接。這是一個比較“緩和”的關閉連接方式,但是如果服務器對QUIT命令返回錯誤時,會拋出異常。
  • FTP.close():單方面的關閉掉連接,不應該用在已經關閉的連接之后,例如不應用在FTP.quit()之后。

下載、上傳文件

#!/usr/bin/python
# -*- coding: utf-8 -*-
# @Time    : 2018/8/6 17:17
# @File    : ftpclient.py
# @Software: PyCharm



# FTP操作
from ftplib import FTP  # 加載ftp模塊
from ftplib import error_perm
from utils import file_util
import os
import time
import socket
from concurrent.futures import ThreadPoolExecutor

host = '127.0.0.1'
username = 'egon'
password = '123456'
file = '1.txt'
port = 2111


def ftpconnect(host, port, username, password):
    ftp = FTP()
    # ftp.set_debuglevel(2)         #打開調試級別2,顯示詳細信息
    ftp.encoding = 'utf-8'  # 解決中文編碼問題,默認是latin-1
    try:
        ftp.connect(host, port)  # 連接
        ftp.login(username, password)  # 登錄,如果匿名登錄則用空串代替即可
        print(ftp.getwelcome())  # 打印歡迎信息
    except(socket.error, socket.gaierror):  # ftp 連接錯誤
        print("ERROR: cannot connect [{}:{}]" .format(host, port))
        return None
    except error_perm:  # 用戶登錄認證錯誤
        print("ERROR: user Authentication failed ")
        return None
    return ftp


def is_ftp_file(ftp_conn, ftp_path):
    try:
        if ftp_path in ftp_conn.nlst(os.path.dirname(ftp_path)):
            return True
        else:
            return False
    except error_perm:
        return False


def downloadfile(ftp, remotepath, localpath):
    """
     下載文件
    :param ftp:
    :param remotepath:
    :param localpath:
    :return:
    """
    bufsize = 1024  # 設置緩沖塊大小
    fp = open(localpath, 'wb')  # 以寫模式在本地打開文件

    res = ftp.retrbinary(
        'RETR ' + remotepath,
        fp.write,
        bufsize)  # 接收服務器上文件並寫入本地文件
    if res.find('226') != -1:
        print('download file complete', localpath)
    ftp.set_debuglevel(0)  # 關閉調試
    fp.close()  # 關閉文件


def uploadfile(ftp, remotepath, localpath):
    """
    上傳文件
    :param ftp:
    :param remotepath:
    :param localpath:
    :return:
    """
    bufsize = 1024
    fp = open(localpath, 'rb')
    res = ftp.storbinary('STOR ' + remotepath, fp, bufsize)  # 上傳文件
    if res.find('226') != -1:
        print('upload file complete', remotepath)
    ftp.set_debuglevel(0)
    fp.close()
def ftp_theadpool(func, ftp, file_list):
    """
    通過線程池調用上傳文件列表
    :param func:
    :param file_list:
    :return:
    """
    pool = ThreadPoolExecutor(6)
    for remotepath, localpath in file_list:
        pool.submit(func, ftp, remotepath, localpath)
    pool.shutdown()


if __name__ == "__main__":
    ftp = ftpconnect(host, port, username, password)
    file_list = ftp.nlst()
    print(file_list)
    # 將傳輸模式改為二進制模式 ,避免提示 ftplib.error_perm: 550 SIZE not allowed in ASCII
    # mode錯誤
    ftp.voidcmd('TYPE I')
    file_size = ftp.size("sqldeveloper-3.1.07.42.zip")  # 文件大小

    print('filesize [{}]'.format(file_util.bytes2human(file_size)))
    start = time.time()
    downloadfile(ftp, "sqldeveloper-3.1.07.42.zip", "e:/x.zip")
    end = time.time()
    print('consume time [{}]'.format(end - start))

    if '20180910' not in file_list:  # 創建目錄
        res = ftp.mkd('20180910')
        print('mk ', res)


    ftp.cwd('20180910')  # 進入到新目錄
    print("FTP當前路徑:", ftp.pwd())
    print("文件信息:", ftp.nlst())

    uploadfile(ftp, "testup.zip", "e:/x.zip") # 上傳文件
    # ftp.cwd('20180910')
    # pwd_path = ftp.pwd()
    # print("FTP當前路徑:", pwd_path)
    # print("文件信息:", ftp.nlst())
    ftp.quit()

  

帶進度條下載文件

from ftplib import FTP
from ftplib import error_perm
import os
import socket
import os
import time
from utils import my_logset
from utils.time_utils import run_time
import sys
import math
from utils import file_util

"""
ftp操作上傳和下載
"""


class FTP_OPS(object):
    """
    ftp文件操作
    """

    def __init__(self, log_file, ftp_ip, ftp_port, ftp_user, ftp_pwd):
        self.db_log = my_logset.get_mylogger("ftp", log_file)
        self.ftp_ip = ftp_ip
        self.ftp_port = ftp_port
        self.ftp_user = ftp_user
        self.ftp_pwd = ftp_pwd

    def ftp_connect(self):
        """
        連接ftp
        :return:
        """
        socket.setdefaulttimeout(160)  # 超時FTP時間設置為60秒
        ftp = FTP()
        ftp.connect(host=self.ftp_ip, port=self.ftp_port)
        ftp.set_debuglevel(2)  # 開啟調試模式
        ftp.encoding = 'utf-8'

        try:
            ftp.login(self.ftp_user, self.ftp_pwd)
            self.db_log.info(
                '[{}]login ftp {}'.format(
                    self.ftp_user,
                    ftp.getwelcome()))  # 打印歡迎信息

        except(socket.error, socket.gaierror):  # ftp 連接錯誤
            self.db_log.warn(
                "ERROR: cannot connect [{}:{}]".format(
                    self.ftp_ip, self.ftp_port))
            return None

        except error_perm:  # 用戶登錄認證錯誤
            self.db_log.warn("ERROR: user Authentication failed ")
            return None
        except Exception as e:
            print(e)
            return None
        return ftp

    @run_time
    def upload_file(self, ftp: FTP, remotepath: str,
                    localpath: str, file: str):
        """
         # 從本地上傳文件到ftp
        :param ftp: ftp對象
        :param remotepath: ftp遠程路徑
        :param localpath: 本地
        :return:
        """
        flag = False
        buffer_size = 10240  # 默認是8192
        print(ftp.getwelcome())  # 顯示登錄ftp信息

        fp = open(os.path.join(localpath, file), 'rb')

        try:
            ftp.cwd(remotepath)  # 進入遠程目錄
            self.db_log.info(
                "found folder [{}] in ftp server, upload processing.".format(remotepath))
            print('進入目錄', ftp.pwd())
            # 將傳輸模式改為二進制模式 ,避免提示 ftplib.error_perm: 550 SIZE not allowed in
            # ASCII
            ftp.voidcmd('TYPE I')
            ftp.storbinary('STOR ' + file, fp, buffer_size)
            ftp.set_debuglevel(0)
            self.db_log.info("上傳文件 [{}] 成功".format(file))
            flag = True
        except error_perm as e:
            self.db_log.warn('文件[{}]傳輸有誤,{}'.format(file, str(e)))
        except TimeoutError:
            self.db_log.warn('文件[{}]傳輸超時'.format(file))
            pass
        except Exception as e:
            self.db_log.warn('文件[{}]傳輸異常'.format(file, str(e)))
            pass
        finally:
            fp.close()

        return {'file_name': file, 'flag': flag}

    def download_file(self, ftp_file_path, dst_file_path):
        """
        從ftp下載文件到本地
        :param ftp_file_path: ftp下載文件
        :param dst_file_path: 本地存放
        :return:
        """
        buffer_size = 10240  # 默認是8192
        ftp = self.ftp_connect()
        print(ftp.getwelcome())  # 顯示登錄ftp信息

        # 將傳輸模式改為二進制模式 ,避免提示 ftplib.error_perm: 550 SIZE not allowed in ASCII
        ftp.voidcmd('TYPE I')
        remote_file_size = ftp.size(ftp_file_path)  # 文件總大小

        print('remote filesize [{}]'.format(remote_file_size))
        cmpsize = 0  # 下載文件初始大小
        lsize = 0
        # check local file isn't exists and get the local file size
        if os.path.exists(dst_file_path):
            lsize = os.stat(dst_file_path).st_size
        if lsize >= remote_file_size:
            print('local file is bigger or equal remote file')
            return
        start = time.time()
        conn = ftp.transfercmd('RETR {0}'.format(ftp_file_path), lsize)

        f = open(dst_file_path, "ab")
        while True:
            data = conn.recv(buffer_size)
            if not data:
                break
            f.write(data)
            cmpsize += len(data)
            self.progressbar(cmpsize, remote_file_size)
            # print(
            #      '\b'*30, 'download process:%.2f%%' %
            #     (float(cmpsize) / remote_file_size * 100))
            # ftp.retrbinary(
            #     'RETR {0}'.format(ftp_file_path),
            #     f.write,
            #     buffer_size)
        f.close()
        try:
            ftp.voidcmd('NOOP')
            print('keep alive cmd success')
            ftp.voidresp()
            print('No loop cmd')
            conn.close()
            ftp.quit()
        except Exception as e:
            pass
        finally:
            end = time.time()
            print('consume time [{}]'.format(end - start))
            file_size = os.stat(dst_file_path).st_size
            print('local filesize [{}] md5:[{}]'.format(
                file_size, file_util.get_md5(dst_file_path)))

        def progressbar(cur, total):
            """
              進度條顯示
              cur表示當前的數值,total表示總的數值。
            :param cur:
            :param total:
            :return:
            """
            percent = '{:.2%}'.format(cur / total)
            sys.stdout.write('\r')
            sys.stdout.write('[%-50s] %s' %
                             ('=' * int(math.floor(cur * 50 / total)), percent))
            sys.stdout.flush()
            if cur == total:
                sys.stdout.write('\n')


if __name__ == '__main__':
    host = "10.0.0.1"
    username = "test"
    password = "test"
    port = "21"
    ftp_file_path = "/data/an/1.zip"
    dst_file_path = "/data/tmp/1.zip"
    ftp = FTP_OPS(host=host, username=username, password=password, port=port)
    ftp.download_file(ftp_file_path=ftp_file_path, dst_file_path=dst_file_path)

 

 

  

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM