xiao-apple36

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)

 

 

  

 

分类:

技术点:

相关文章:

  • 2021-08-23
  • 2021-12-16
  • 2021-08-12
  • 2022-03-06
  • 2022-12-23
  • 2022-12-23
  • 2021-09-20
猜你喜欢
  • 2022-12-23
  • 2022-03-04
  • 2021-07-13
  • 2021-08-01
  • 2021-12-13
  • 2021-07-01
相关资源
相似解决方案