栏目分类:
子分类:
返回
文库吧用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
文库吧 > IT > 软件开发 > 后端开发 > Python

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

Python 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

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 traceback
import logging
import os
"""
    V1.0:
        初步实现功能
    V1.1:
        目录下载方式进行优化,目录下存在目录的话,也会将该目录下的文件进行下载
        进行文件对比的优化,进行对比的目录中存在目录的话,也会将该目录下的文件进行对比
    
    备注:
        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, host, port=21, username=None, password=None):
        """ 初始化 FTP 客户端
        参数:
                 host:ip地址
                 port:端口号
        """
        self.log()
        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]))



if __name__ == '__main__':
    My_FTP = MyFTP("10.0.1.4")

    My_FTP.FILE_Compare_EXECUTE("H:/1/", "H:/2/")

    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/")
    '''


由于在Linux系统下创建目录还需要给权限,不然没法直接上传文件,所以就懒得写上传目录的部分了,有需要的小伙伴可以参考一下代码中《下载整个目录》的部分然后自己写。

转载请注明:文章转载自 www.wk8.com.cn
本文地址:https://www.wk8.com.cn/it/1037307.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 wk8.com.cn

ICP备案号:晋ICP备2021003244-6号