#!/usr/bin/python
#coding=utf-8
'''
ftp自动下载、自动上传脚本,可以递归目录操作
'''
from ftplib import FTP
import os,sys,string,datetime,time
import socket
class MYFTP:
def __init__(self, hostaddr, username, password, remotedir, port=21): #初始化类
self.hostaddr = hostaddr #IP
self.username = username #用户名
self.password = password #密码
self.remotedir = remotedir #远程文件夹
self.port = port #端口号
self.ftp = FTP() #ftp #设置变量
self.file_list = [] #文件列表
# self.ftp.set_debuglevel(2) #打开调试级别2,显示详细信息
def __del__(self):
self.ftp.close() #关闭ftp连接
# self.ftp.set_debuglevel(0)
def login(self):
ftp = self.ftp
try:
timeout = 60
socket.setdefaulttimeout(timeout) #默认ftp连接超时时间60秒
ftp.set_pasv(True) #下载模式 被动模式 false禁用被动
print '开始连接到 %s' %(self.hostaddr) #打印连接信息
ftp.connect(self.hostaddr, self.port) #连接
print '成功连接到 %s' %(self.hostaddr) #打印连接信息
print '开始登录到 %s' %(self.hostaddr) #打印连接信息
ftp.login(self.username, self.password) #登录 匿名登录的话使用空串
print '成功登录到 %s' %(self.hostaddr) #打印连接信息
debug_print(ftp.getwelcome()) #打印出FTP欢迎信息
except Exception:
deal_error("连接或登录失败") #登录异常
try:
ftp.cwd(self.remotedir) #设置FTP当前操作的路径为 remotedir
except(Exception):
deal_error('切换目录失败') #目录异常
def is_same_size(self, localfile, remotefile):#判断本地是否有相同文件
try:
remotefile_size = self.ftp.size(remotefile) #远程文件大小
except:
remotefile_size = -1
try:
localfile_size = os.path.getsize(localfile) #本地文件大小
except:
localfile_size = -1
debug_print('lo:%d re:%d' %(localfile_size, remotefile_size),)
if remotefile_size == localfile_size: #文件大小是否相同
return 1
else:
return 0
def download_file(self, localfile, remotefile): #下载文件到本地
if self.is_same_size(localfile, remotefile): #判断本地是否有相同文件 函数is_same_size
debug_print('%s 文件大小相同,无需下载' %localfile) #文件相同 跳过下载
return
else:
debug_print('>>>>>>>>>>>>下载文件 %s ... ...' %localfile) #日志
#return
#下载FTP文件
file_handler = open(localfile, 'wb')
self.ftp.retrbinary('RETR %s'%(remotefile), file_handler.write)
file_handler.close()
def download_files(self, localdir='./', remotedir='./'): #下载文件
try:
self.ftp.cwd(remotedir) #设置FTP当前操作的路径为 remotedir
except:
debug_print('目录%s不存在,继续...' %remotedir) #远程目录remotedir不存在
return
if not os.path.isdir(localdir): #判断本地目录是否存在
os.makedirs(localdir) #不存在则创建
debug_print('切换至目录 %s' %self.ftp.pwd()) #打印日志信息
self.file_list = [] #初始化清空列表file_list 存放获取到的文件列表
self.ftp.dir(self.get_file_list)
#查看目录下的所有文件 目录为get_file_list函数的返回值 详细见get_file_list函数
#get_file_list函数会将获取到的文件信息添加到 file_list
remotenames = self.file_list #设置变量remotenames的值为获取到的文件 以下看到遍历信息[0][1] 可知获取文件信息时返回值
#print(remotenames)
#return
print remotenames #打印
for item in remotenames: #遍历remotenames
filetype = item[0] #类型 文件夹还是文件
filename = item[1] #文件名
local = os.path.join(localdir, filename) #本地目录和文件名拼接
if filetype == 'd': #类型为文件夹
self.download_files(local, filename) #递归下载 目录切换
elif filetype == '-': #类型为文件
self.download_file(local, filename) #下载文件到本地 下载文件具体见函数download_file
self.ftp.cwd('..') #目录下不存在目录时候结束递归切换到上一层目录继续下载
debug_print('返回上层目录 %s' %self.ftp.pwd()) #日志信息
'''
#上传
'''
def upload_file(self, localfile, remotefile): #上传文件
if not os.path.isfile(localfile): #本地文件不存在退出
return
if self.is_same_size(localfile, remotefile): #存在相同大小文件 跳过
debug_print('跳过[相等]: %s' %localfile)
return
#FTP上传文件
file_handler = open(localfile, 'rb')
self.ftp.storbinary('STOR %s' %remotefile, file_handler)
file_handler.close()
debug_print('已传送: %s' %localfile)#日志
def upload_files(self, localdir='./', remotedir = './'): #上传文件
if not os.path.isdir(localdir): #本地目录不存在退出
return
localnames = os.listdir(localdir) #列出本地文件夹
self.ftp.cwd(remotedir) #设置远程ftp操作目录
for item in localnames: #遍历本地目录
src = os.path.join(localdir, item)
if os.path.isdir(src): #文件夹 递归
try:
self.ftp.mkd(item) #新建远程目录
except:
debug_print('目录已存在 %s' %item)
self.upload_files(src, item)
else:
self.upload_file(src, item) #上传文件
self.ftp.cwd('..') #目录下不存在目录时候结束递归切换到上一层目录继续
def get_file_list(self, line): #查看目录下的所有文件
ret_arr = [] #初始化ret_arr
file_arr = self.get_filename(line) #获取文件名 方法get_filename
if file_arr[1] not in ['.', '..']: #去掉 '.' '..'
self.file_list.append(file_arr) #文件信息添加到类的file_list
def get_filename(self, line): #文件信息截取文件名和类型
# pass
#'''
#文件信息
# 权限-文件d文件夹 文件或文件夹名
# -rw-r--r-- 1 0 0 1234 May 31 09:56 file.xxx
# drwxr-xr-x 2 0 0 1234 May 31 2020 this_is_dir
#
#类型截取第一个字符串 'd' '-' name截取最后一个空格之后的 可以rfind(' ') 或者split() 但是都不适用于文件名带空格
#若截取时间信息的 : 往后移动 适用于文件名带空格的文件 但是有些信息不全的文件时间信息只有年份 没有具体时间点
#
# 此处是测试内容
# 要求:完善这个方法实现FTP递归下载
return [line[0],line.split()[-1]] ########此处为补全
#'''
def debug_print(s):
print (s)
def deal_error(e):
timenow = time.localtime()
datenow = time.strftime('%Y-%m-%d', timenow)
logstr = '%s 发生错误: %s' %(datenow, e)
debug_print(logstr)
file.write(logstr)
sys.exit()
if __name__ == '__main__':
file = open("log.txt", "a")
timenow = time.localtime()
datenow = time.strftime('%Y-%m-%d', timenow)
logstr = datenow
# 配置如下变量
hostaddr = '168.7.63.172' # ftp地址
username = 'root' # 用户名
password = 'root1234' # 密码
port = 21 # 端口号
rootdir_local = '/root/abc' # 本地目录
rootdir_remote = '/etc/vsftpd' # 远程目录
f = MYFTP(hostaddr, username, password, rootdir_remote, port) #初始化类MYFTP:f
f.login() #登录远程ftp
f.download_files(rootdir_local, rootdir_remote) #下载文件 参数本地路径 远程路径
timenow = time.localtime()
datenow = time.strftime('%Y-%m-%d', timenow)
logstr += " - %s 成功执行了备份\n" %datenow
debug_print(logstr)
file.write(logstr)
file.close()