Python ftplibo文件上传下载及对比功能

背景:最近工作有需要自动化FTP上传下载数据并进行对比的功能,本来是打算直接在网上搜现成的来改一下的,但是整合完发现,一次性下载超过200多个文件的时候就会报错,而且看别人写的代码是一件痛苦的事情,所以就干脆搜了点资料自己写了,现在记个笔记,有需要的可以拿现成的用。

目录

ftplib模块的一些基本的东西:

OS模块的一些操作:

自己的实现部分:


 ftplib模块的一些基本的东西:

from ftplib import FTP			# 导入FTP模块
ftp = FTP()						# 设置变量
ftp.set_debuglevle(2)			# 设置实例的调试级别,0:不输出(缺省值),1:中等调试输出,通常每个请求一行,2:显示详细信息
ftp.connect(host='', port=0)	# 连接到给定的主机和端口(默认21),很少需要指定其他端口号。
ftp.getwelcome()				# 打印出欢迎信息
ftp.login('user', 'password')	# 以用户身份登录
ftp.abort()						# 中止正在进行的文件传输
ftp.retrbinary("RETR filename", fp, blocksize)		# 接受服务器上的文件并写入本地文件
ftp.storbinary("STOR filename", fp, blocksize)		# 以二进制传输模式存储文件,即上传文件至FTP服务器
ftp.set_pasv()					# 设置模式, true为被动模式(默认值),false为主动模式
ftp.quit()						# 退出ftp

ftp.cwd(pathname)				# 设置FTP当前操作的路径
ftp.dir()						# 显示目录下所有目录信息
ftp.nlist()						# 获取目录下的文件
ftp.mkd(pathname)				# 新建远程目录
ftp.pwd()						# 返回当前所在位置
ftp.rmd(dirname)				# 删除远程目录
ftp.delete(filename)			# 删除远程文件
ftp.rename(fromname, toname)	# 将fromname修改为toname
ftp.size(filename)				# 请求服务器上名为filename的文件的大小

 OS模块的一些操作:

方法说明
os.mkdir创建目录

os.rmdir删除目录

os.rename重命名

os.remove删除文件

os.getcwd获取当前工作路径

os.walk遍历目录

os.path.join连接目录与文件名

os.path.split分割文件名与目录

os.path.abspath获取绝对路径

os.path.dirname获取路径

os.path.basename获取文件名或文件夹名

os.path.splitext分离文件名与扩展名

os.path.isfile判断给出的路径是否是一个文件

os.path.isdir判断给出的路径是否是一个目录

自己的实现部分:

#! /usr/bin/python # -*- coding: utf-8 -*
import re
import sys
import datetime, time
from ftplib import FTP  # 定义了FTP类,实现ftp上传和下载
import logging
import os
"""
    V1.0:
        初步实现功能
    V1.1:
        目录下载方式进行优化,目录下存在目录的话,也会将该目录下的文件进行下载
        进行文件对比的优化,进行对比的目录中存在目录的话,也会将该目录下的文件进行对比
    V1.2:
        实现整个目录上传(目录中包含目录也可以)
        ##待验证##
    
    备注:
        Linux系统,所下载的文件权限(其他用户权限)没有读权限时会报错:ftplib.error_perm: 550 Failed to open file.
        -rw-rw----    1 ftp      1000     291151872 Mar 29 20:55 sj1.dat    #无法下载
        -rw-rw-rw-    1 ftp      1000      11829248 Mar 29 20:55 sj2.dat    #可下载
        -rw-------    1 ftp      1000      17743872 Mar 29 20:55 sj3.dat    #无法下载
        
        从左至右:-rwxrwxrwx
            最左侧1位d表示文件夹,l表示连接文件,-表示文件
            2-4位数字代表文件所有者的权限
            5-7位数字代表同组用户的权限
            8-10数字代表其他用户的权限
        权限命令:chmod 777 文件名
            无权限(-)=0,读(r)=4,写(w)=2,执行(x)=1,例如:读+写+执行=4+2+1=7
    
"""


class MyFTP:
    """
        ftp自动下载、自动上传脚本,可以递归目录操作
    """

    def __init__(self):
        self.log()


    def FTP_register(self, host, port=21, username=None, password=None):
        """
        ”初始化 FTP 客户端"
        :param host: 服务器ip地址
        :param port: 端口号
        :param username: 用户名
        :param password: 密码
        :return:
        """
        # self.logger.info("__init__()---> host = %s ,port = %s ,username=%s ,password = %s ," % (host, port, username, password))
        self.ftp = FTP()
        self.ftp.set_debuglevel(2)
        self.ftp.connect(host, port)
        self.ftp.login(username, password)
        # 设置下编码方式、主\被动模式、缓冲区大小,打印欢迎信息
        self.ftp.encoding = 'gbk'
        self.ftp.set_pasv(True)
        self.BLOCKSIZE = 8192
        self.logger.info(self.ftp.getwelcome())


    def log(self):
        """
            创建日志器
            设置日志打印级别
            创建一个handler,用于写入日志文件
            mode = "a":追加,“w”:覆盖
        """
        self.logger = logging.getLogger()
        self.logger.setLevel(logging.INFO)
        fh = logging.FileHandler(filename="log.log", mode='w', encoding='utf-8')  # 指定utf-8格式编码,避免输出的日志文本乱码
        fh.setLevel(logging.DEBUG)
        #创建一个handler,用于将日志输出到控制台
        ch = logging.StreamHandler()
        ch.setLevel(logging.DEBUG)
        # 定义handler的输出格式
        formatter = logging.Formatter('%(asctime)s - %(filename)s[line:%(lineno)d] - %(levelname)s: %(message)s')
        fh.setFormatter(formatter)
        ch.setFormatter(formatter)
        # 给logger添加handler
        self.logger.addHandler(fh)
        self.logger.addHandler(ch)


    def FILE_Compare(self, path_0, path_1):
        '''
        进行文件内容比较
        '''
        with open(path_0, 'rb') as file_byte:
            a = file_byte.read()
        with open(path_1, 'rb') as file_byte1:
            b = file_byte1.read()
        if a == b:
            self.logger.debug('内容对比:YES-->:[%s<--->%s]' % (path_0, path_1))
        else:
            self.logger.info("内容对比:NO-->:[%s<--->%s]" % (path_0, path_1))
        return


    def Obtain_Directory_list(self, path, a=1):
        """
        “进入指定列表并获取列表下所有文件信息”
        :param      remote_dir: 远程路径
        :return:    输出目录下文件列表
        :param a:   a==0:获取远程路径列表
                    a==1:获取本地路径列表
        :return:
        """

        if a == 0:
            self.ftp.cwd(path) #进入远程路径
            return self.ftp.nlst()#获取路径下文件名
        elif a == 1:
            return os.listdir(path)#获取本地路径下文件名


    def FTP_Download_File(self, local_dir, remote_dir):
        """
        下载单个文件
        :param local_dir:本地路径
        :param remote_dir:远程路径
        :return:
        """
        with open(local_dir, "wb") as f:
            try:
                self.ftp.retrbinary("RETR %s" % remote_dir, f.write, self.BLOCKSIZE)
            except Exception as result:
                self.logger.warning("下载文件%s时发生错误 % s----->可能是文件无读写权限" % (remote_dir, result))
                return

        return()


    def FTP_Upload_File(self, local_dir, remote_dir):
        """
        上传单个文件
        :param local_dir:本地路径
        :param remote_dir:远程路径
        :return:
        """
        with open(local_dir, "rb") as f:
            self.ftp.storbinary("STOR %s" % remote_dir, f, self.BLOCKSIZE)

        return ()


    def FTP_Download_Directory(self, local_dir, remote_dir):
        # """
        # "下载整个目录"
        # :param local_dir:
        # :param remote_dir:
        # :return:
        # """
        # local_dir = local_dir
        # List = self.Obtain_Directory_list(remote_dir, a=0)
        #
        # for a in List:
        #     self.logger.info(local_dir + a + "----kaisi--->" + remote_dir + "/" + a)
        #     self.FTP_Download_File(str(local_dir + a), str(remote_dir + "/" + a))
        #
        return print("该函数已经弃用")


    def FTP_Upload_Directory(self, local_dir, remote_dir):
        """
        “上传整个目录”
        :param local_dir:
        :param remote_dir:
        :return:
        """
        local_dir = local_dir
        List = self.Obtain_Directory_list(local_dir, a=1)

        for a in List:
            self.logger.debug(local_dir + a + "------->" + remote_dir + "/" + a)
            self.FTP_Upload_File(str(local_dir + "/" + a), str(remote_dir + a))

        return


    def FILE_Compare_EXECUTE(self, path_0, path_1):
        """
        “对目录文件进行比较”
        :param path_0: 第一个目录路径
        :param path_1: 第二个目录路径
        :return:

        列表比较方式
        a = [1,0,2]    b = [1,0,0]
        x = [k for k in a if k in b]            x = [1,0]
        x = [k for k in a if k not in b]        x = [2]

        """

        path_0_list = self.Obtain_Directory_list(path_0, a=1)
        path_1_list = self.Obtain_Directory_list(path_1, a=1)
        x = [k for k in path_0_list if k not in path_1_list]
        y = [k for k in path_1_list if k not in path_0_list]
        z = [k for k in path_0_list if k in path_1_list]
        if x or y:
            self.logger.info("丨———————————————↓———————————————————丨")
            self.logger.info("目录" + path_0 + "缺少>>:" + str(y))
            self.logger.info("目录" + path_1 + "缺少>>:" + str(x))
            self.logger.info("丨———————————————↑———————————————————丨")
        else:
            self.logger.debug(">----两个目录文件个数一致,无缺失<----")
        for i in z:
            #判断路径是否为目录,是则进入路径,不是则进行文件比较
            if os.path.isdir(path_0 + i) == True:
                logging.debug("转到目录:--->" + path_0 + i + "/" + "与" + path_1 + i + "/")
                self.FILE_Compare_EXECUTE(path_0 + i + "/", path_1 + i + "/")
            else:
                self.FILE_Compare(path_0 + i, path_1 + i)


    def get_file_name(self, line):
        """ 获取远程路径目录下的文件名
            pos = line.rfind(' '):匹配字符串最后一次出现的地方
            参数:
                line:
        """
        pos = line.rfind(' ')
        while (line[pos] != ' '):
            pos += 1
        while (line[pos] == ' '):
            pos += 1
        file_arr = [line[0], line[pos:]]
        return file_arr


    def FTP_Download_Directory_duo_Directory(self, local_dir, remote_dir):
        """
        "下载整个目录"
        :param local_dir:本地路径
        :param remote_dir:远程路径
        :return:
        """
        local_dir = local_dir
        remote_dir = remote_dir + "/"
        self.ftp.cwd(remote_dir)  # 进入远程路径
        dir_list = []
        self.ftp.dir('.', dir_list.append) #获取本地文件
        list_list = []
        for i in dir_list:
            list_list.append(self.get_file_name(i))
        self.logger.debug(list_list)
        for a in list_list:
            # 判断是否为目录
            if a[0] == "d":
                #判断本地是否存在该目录,没有则创建
                if os.path.exists(local_dir + a[1]) == False:
                    os.mkdir(local_dir + a[1])
                self.logger.debug(local_dir + "/" + a[1] + "/" + "------建文件夹并进入------" + remote_dir + a[1])
                #递归进入下一路径
                self.FTP_Download_Directory_duo_Directory(local_dir + a[1] + "/", remote_dir + a[1])
            elif a[0] == "-":
                self.logger.info(str(local_dir + a[1]) + "-------下载文件-----" + str(remote_dir + a[1]))
                self.FTP_Download_File(str(local_dir + a[1]), str(remote_dir + "/" + a[1]))


    def FTP_Upload_Directory_duo_Directory(self, local_dir, remote_dir):
        """
        “上传整个目录”
        :param local_dir:
        :param remote_dir:
        :return:
        """
        local_dir = local_dir
        remote_dir = remote_dir + "/"
        # 进入远程路径
        self.ftp.cwd(remote_dir)
        list_1 = os.listdir(local_dir)
        for a in list_1:
            b = os.path.join(local_dir, a)
            #判断是否为文件夹
            if os.path.isdir(b):
                dir_list = []
                self.ftp.dir('.', dir_list.append)  # 获取远程路径目录下的文件名
                list_list = []
                for i in dir_list:
                    list_list.append(self.get_file_name(i))
                self.logger.debug(list_list)
                # 校验
                jiao_yan = 0
                for e in list_list:
                    if e[0] == "d" and e[1] == a:
                        jiao_yan = 1
                        self.FTP_Upload_Directory_duo_Directory(local_dir + "/" + a + "/", remote_dir + a)
                if jiao_yan == 0:
                    #创建远程目录
                    self.ftp.mkd(remote_dir + a)
                    self.logger.debug(local_dir + "/" + a + "/" + "------建文件夹并进入------" + remote_dir + a)
                    self.FTP_Upload_Directory_duo_Directory(local_dir + "/" + a + "/", remote_dir + a)
            else:
                self.logger.info(local_dir + a + "-------上传文件-----" + remote_dir + a)
                # print(local_dir + a,remote_dir + a)
                self.FTP_Upload_File(local_dir + a, remote_dir + a)
        return


    def Delete_File(self, vremote_path, TYPE=0):
        """
        删除文件或目录
        :param vremote_path:
        :param TYPE: 0——目录,1——文件
        :return:
        """
        if TYPE == 0:
            if os.path.exists(vremote_path) == False:
                self.ftp.rmd(vremote_path)  # 删除远程目录
        elif TYPE == 1:
            if os.path.exists(vremote_path) == False:
                self.ftp.delete(vremote_path)  # 删除远程文件
        return



if __name__ == '__main__':
    My_FTP = MyFTP()
    My_FTP.FTP_register(host="10.0.1.4")
    My_FTP.FTP_Upload_Directory_duo_Directory("H:/vib/", "/LH_DATA/hdd/clb")
# #   My_FTP.FILE_Compare_EXECUTE("H:/1/", "H:/2/")
#     My_FTP.FTP_Upload_File("'H:/vib/014445/H:/vib/014445/motor_shock_20220806014445.dat'", "/LH_DATA/hdd/log/200001010034-vib.dat")
#
    My_FTP.ftp.close()#退出FTP



    '''
    使用示例

    下载单个文件
        My_FTP.FTP_Download_File("H:/200001010034-vib.dat", "/LH_DATA/hdd/clb/raw/20000101/200001010034-vib.dat")

    上传单个文件
        My_FTP.FTP_Upload_File("H:/200001010034-vib.dat","/LH_DATA/hdd/log/200001010034-vib.dat")

    下载目录:目录中不能有目录,不然可能会报错--------->(弃用,已经被注释)
        My_FTP.FTP_Download_Directory("H:/2/", "/LH_DATA/hdd/clb/raw/20000101")

    下载整个目录:目录中有目录也可下载
        My_FTP.FTP_Download_Directory_duo_Directory("H:/vib/", "/motor/motor/20220806")

    上传目录:目录中不能有目录,不然可能会报错
        My_FTP.FTP_Upload_Directory("H:/2/","/LH_DATA/hdd/log/")

    目录文件对比:目录中不能有目录,不然可能会报错
        My_FTP.FILE_Compare_EXECUTE("H:/1/", "H:/2/")
    '''


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
FTP Library Routines Release 4.0 Thomas Pfau (tfpfau@gmail.com) June 7, 2013 This package implements a callable interface to FTP. The FTP protocol is specified in RFC 959. The library has been tested on linux, OpenVMS and Windows NT. It should also work without major modification on other POSIX systems. All programs using the library should include ftplib.h. FTP开源库。 Miscellaneous Functions FtpInit() - Initialize the library FtpSite() - Send a 'SITE' command FtpLastResponse() - Retrieve last server response FtpSysType() - Determine remote system type FtpSize() - Determine size of remote file FtpSizeLong() - Determine size of remote file FtpModDate() - Determine modification time of file FtpSetCallback() - Establish a callback function FtpClearCallback() - Remove a callback function Server Connection FtpConnect() - Connect to a remote server FtpLogin() - Login to remote machine FtpQuit() - Disconnect from remote server FtpOptions() - Set Connection Options Directory Functions FtpChdir() - Change working directory FtpMkdir() - Create a directory FtpRmdir() - Remove a directory FtpDir() - List a remote directory FtpNlst() - List a remote directory FtpCDUp() - Change to parent directory FtpPwd() - Determine current working directory File to File Transfer FtpGet() - Retreive a remote file FtpPut() - Send a local file to remote FtpDelete() - Delete a remote file FtpRename() - Rename a remote file File to Program Transfer These routines allow programs access to the data streams connected to remote files and directories. FtpAccess() - Open a remote file or directory FtpRead() - Read from remote file or directory FtpWrite() - Write to remote file FtpClose() - Close data connection Utilities qftp - Command line ftp utility
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

hi-那个谁

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值