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)

 

 

  

 

posted @ 2018-09-21 16:35  一只小小的寄居蟹  阅读(25085)  评论(1编辑  收藏  举报