功能介绍:创建定时任务,通过输入执行一段sql语句查找数据库中文件名称,通过文件名称前往指定本地库将指定文件名称的文件上传到指定FTP文件夹中
python代码:
ftp.py
#!/usr/bin/python
# -*- coding: UTF-8 -*-
import datetime
import threading
from ftplib import FTP
import sys
import os
import time
import socket
from tkinter import *
from ftp上传工具.MysqlHelper import MysqlHelper
class MyFtpGUI:
def __init__(self):
self.init_Menu()
def init_Menu(self):
self.top = Tk()
# self.top.geometry("600x550")
self.top.minsize(800, 720)
self.top.maxsize(800, 720)
self.top.title("Author:xuhao QQ:916295795 Email:[email protected]")
self.mainframe = Frame(self.top)
self.init_FTPGUI()
# 初始化合同公示GUI
def init_FTPGUI(self):
self.mainframe.pack_forget()
self.frame = Frame(self.top)
self.label = Label(self.frame,
text='FTP文件上传程序v2.0')
self.label.pack()
self.data = []
"""消息栏容器"""
# frame容器
self.dirfm = Frame(self.frame)
# 下滑框
self.dirsb = Scrollbar(self.dirfm)
self.v = StringVar()
self.main = Listbox(self.dirfm, listvariable=self.v, height=15,
width=50, yscrollcommand=self.dirsb.set)
self.dirsb.config(command=self.main.yview)
"""数据库配置"""
self.dblabel = Label(self.frame,
text='数据库配置')
self.dblabel.pack()
self.host = StringVar(self.frame)
self.port = StringVar(self.frame)
self.user = StringVar(self.frame)
self.passwd = StringVar(self.frame)
self.db = StringVar(self.frame)
self.charset = StringVar(self.frame)
self.AutoStringVar([self.host, self.port, self.user, self.passwd, self.db, self.charset])
if not os.path.exists("setting.txt"):
open("setting.txt", "w", encoding="utf8")
"""FTP配置"""
self.dblabel1 = Label(self.frame,
text='FTP配置')
self.dblabel1.pack()
self.ftp_address = StringVar(self.frame)
self.ftp_port = StringVar(self.frame)
self.ftp_username = StringVar(self.frame)
self.ftp_password = StringVar(self.frame)
self.AutoStringVar([self.ftp_address, self.ftp_port, self.ftp_username, self.ftp_password])
"""文件路径配置"""
self.dblabel2 = Label(self.frame,
text='路径配置')
self.dblabel2.pack()
self.file_base = StringVar(self.frame)
self.file_goal = StringVar(self.frame)
self.file_type = StringVar(self.frame)
self.AutoStringVar([self.file_base, self.file_goal, self.file_type])
# 设置所有默认设置
self.setSetting()
"""消息栏"""
self.windowlabel = Label(self.frame,
text='FTP文件上传实时消息栏')
self.windowlabel.pack()
self.dirsb.pack(side=RIGHT, fill=Y)
self.main.pack(side=LEFT, fill=BOTH)
self.dirfm.pack()
"""SQL查询"""
self.cwd = StringVar(self.frame)
self.cwd.set("请输入SQL查询语句")
# 装载了StringVar
self.dirn = Entry(self.frame, width=50,
textvariable=self.cwd)
self.dirn.pack()
# 又是一个容器
self.bfm = Frame(self.frame)
self.saveSet = Button(self.bfm, text='保存配置',
command=self.saveSetting,
activeforeground='white',
activebackground='blue')
self.uploadfile = Button(self.bfm, text='上传文件',
command=lambda: thread_it(self.uploadFileToFTP, 300),
activeforeground='white',
activebackground='blue')
self.clear = Button(self.bfm, text='清空SQL',
command=self.clearInput,
activeforeground='white',
activebackground='green')
self.quit = Button(self.bfm, text='退出程序',
command=self.top.quit,
activeforeground='white',
activebackground='red')
self.saveSet.pack(side=LEFT)
self.uploadfile.pack(side=LEFT)
self.clear.pack(side=LEFT)
self.quit.pack(side=LEFT)
self.bfm.pack()
self.frame.pack()
def insert(self, str):
self.data.append(str)
self.v.set(self.data)
# 在最底部更新
self.main.see(END)
def saveSetting(self):
f = open("setting.txt", "w", encoding="utf8")
newSetting = [self.host.get(),
self.port.get(),
self.user.get(),
self.passwd.get(),
self.db.get(),
self.charset.get(),
self.ftp_address.get(),
self.ftp_port.get(),
self.ftp_username.get(),
self.ftp_password.get(),
self.file_base.get(),
self.file_goal.get(),
self.file_type.get()]
f.write(str(newSetting))
f.close()
self.insert('配置文件保存成功!')
def setSetting(self):
f = open("setting.txt", "r", encoding="utf8")
f.seek(0, 0)
if f.read() != "":
f.seek(0, 0)
import ast
result = ast.literal_eval(str(f.read()))
if len(result) > 0:
self.host.set(result[0])
self.port.set(result[1])
self.user.set(result[2])
self.passwd.set(result[3])
self.db.set(result[4])
self.charset.set(result[5])
self.ftp_address.set(result[6])
self.ftp_port.set(result[7])
self.ftp_username.set(result[8])
self.ftp_password.set(result[9])
self.file_base.set(result[10])
self.file_goal.set(result[11])
self.file_type.set(result[12])
self.insert("配置文件读取成功!")
else:
self.initAddr()
f.close()
def initAddr(self):
self.setTitle(self.host, "数据库连接地址:localhost")
self.setTitle(self.port, "端口:8080")
self.setTitle(self.user, "数据库用户名:root")
self.setTitle(self.passwd, "数据库密码:123")
self.setTitle(self.db, "数据库名称:xuhao")
self.setTitle(self.charset, "编码:utf8")
self.setTitle(self.ftp_address, "FTP地址:192.168.1.106")
self.setTitle(self.ftp_port, "FTP端口:21")
self.setTitle(self.ftp_username, "FTP登录账号:admin")
self.setTitle(self.ftp_password, "FTP登录密码:123")
self.setTitle(self.file_base, "本地文件路径:c:/")
self.setTitle(self.file_goal, "目标文件路径:/dir/")
self.setTitle(self.file_type, "文件类型:.jpg")
self.insert("配置文件读取失败,已自动创建默认配置文件!")
self.saveSetting()
def setTitle(self, name, title):
"""
设置文本文件
:param name:
:param title:
:return:
"""
name.set(title)
def AutoStringVar(self, namelist):
"""
自动装载StringVar
:param namelist: 待装载名列表list
:return: none
"""
for name in namelist:
self.dirn = Entry(self.frame, width=50,
textvariable=name)
self.dirn.pack()
# 清空输入
def clearInput(self):
self.cwd.set("")
self.insert("SQL输入框已清空!")
def uploadFileToFTP(self, n):
"""
定时器上传文件到FTP上
:return:
"""
self.initFTP()
self.TimerStarter(n)
def initFTP(self):
self.ftpFuc = MyFtpFunction(getTrueInput(":", self.ftp_address.get()), self.main, self.data, self.v,
int(getTrueInput(":", self.ftp_port.get())))
self.ftpFuc.login(getTrueInput(":", self.ftp_username.get()),
getTrueInput(":", self.ftp_password.get()))
def TimerStarter(self, n):
"""
定时器每隔n秒执行一次
:return:
"""
while True:
result = executeSQL(getTrueInput(":", self.host.get()),
int(getTrueInput(":", self.port.get())),
getTrueInput(":", self.user.get()),
getTrueInput(":", self.passwd.get()),
getTrueInput(":", self.db.get()),
getTrueInput(":", self.charset.get()), self.cwd.get())
self.insert(str(result))
self.insert("开始将文件上传至FTP中...")
if str(type(result)) == "":
# 有结果
self.insert("SQL语句执行成功")
self.insert("目标上传文件数量:%s个" % len(result))
number = 1
for item in result:
self.insert("当前上传文件为第%s个" % number)
if str(item[0]).__contains__(getTrueInput(":", self.file_type.get())):
try:
self.ftpFuc.upload_file(
getTrueInput(":", self.file_base.get()) + item[0],
getTrueInput(":", self.file_goal.get()) + item[
0])
except Exception:
self.initFTP()
self.ftpFuc.upload_file(
getTrueInput(":", self.file_base.get()) + item[0],
getTrueInput(":", self.file_goal.get()) + item[
0])
else:
try:
self.ftpFuc.upload_file(
getTrueInput(":", self.file_base.get()) + item[0] + getTrueInput(":",
self.file_type.get()),
getTrueInput(":", self.file_goal.get()) + item[
0] + getTrueInput(":", self.file_type.get()))
except Exception:
self.initFTP()
self.ftpFuc.upload_file(
getTrueInput(":", self.file_base.get()) + item[0] + getTrueInput(":",
self.file_type.get()),
getTrueInput(":", self.file_goal.get()) + item[
0] + getTrueInput(":", self.file_type.get()))
number += 1
else:
self.insert("文件上传完毕")
else:
# 无结果
self.insert("SQL语句执行失败,请检查是否存在错误!")
break
self.insert("已触发定时器,等待执行新的上传任务")
self.setTitle(self.cwd, getNewTime(self.cwd.get(), 0, 0, 0, n))
time.sleep(n)
def getTrueInput(flag, str):
"""
获取字符串中flag后面的值
输入示例:类型:tuple
:param str: 待处理字符串
:return:flag后面跟着的值
"""
return str.split(flag)[1]
def getNewTime(sql, d, h, m, s):
"""
获取新的加时间,sql语句中需要带datetime时间并使用单引号
示例:"select name from phototest where time >='2019-12-20 00:00:00' and time <= '2019-12-20 00:00:05';"
:param sql:sql语句
:param d:天
:param h:时
:param m:分
:param s:秒
:return:结果
"""
data = sql.split("'")
data[1] = "'" + data[3] + "'"
data[3] = "'" + str(
datetime.datetime.strptime(data[3], "%Y-%m-%d %H:%M:%S") + datetime.timedelta(days=d, hours=h, minutes=m,
seconds=s)) + "'"
data = "".join(data)
print(data)
return data
def thread_it(func, *args):
"""
将函数打包进线程
:param func:
:param args:
:return:
"""
# 创建
t = threading.Thread(target=func, args=args)
# 守护 !!!
t.setDaemon(True)
# 启动
t.start()
# 阻塞--卡死界面!
# t.join()
def executeSQL(host, port, user, passwd, db, charset, sql):
"""
执行sql语句获取返回值
:param host:
:param port:
:param user:
:param passwd:
:param db:
:param charset:
:param sql:
:return: tuple
"""
helper = MysqlHelper(host=host, port=port, user=user, passwd=passwd, db=db,
charset=charset)
result = helper.all(sql)
print(result)
return result
class MyFtpFunction:
"""
ftp自动下载、自动上传脚本,可以递归目录操作
"""
def __init__(self, host, listbox: Listbox, data, v: StringVar, port=21):
""" 初始化 FTP 客户端
参数:
host:ip地址
port:端口号
"""
# print("__init__()---> host = %s ,port = %s" % (host, port))
self.host = host
self.listbox = listbox
self.data = data
self.v = v
self.port = port
self.ftp = FTP()
# 重新设置下编码方式
self.ftp.encoding = 'gbk'
self.log_file = open("log.txt", "a")
self.file_list = []
def login(self, username, password):
""" 初始化 FTP 客户端
参数:
username: 用户名
password: 密码
"""
try:
timeout = 60
socket.setdefaulttimeout(timeout)
# 0主动模式 1 #被动模式
self.ftp.set_pasv(False)
# 打开调试级别2,显示详细信息
# self.ftp.set_debuglevel(2)
self.debug_print('开始尝试连接到 %s' % self.host)
self.ftp.connect(self.host, self.port)
self.debug_print('成功连接到 %s' % self.host)
self.debug_print('开始尝试登录到 %s' % self.host)
self.ftp.login(username, password)
self.debug_print('成功登录到 %s' % self.host)
self.debug_print(self.ftp.welcome)
except Exception as err:
self.deal_error("FTP 连接或登录失败 ,错误描述为:%s" % err)
pass
def is_same_size(self, local_file, remote_file):
"""判断远程文件和本地文件大小是否一致
参数:
local_file: 本地文件
remote_file: 远程文件
"""
try:
remote_file_size = self.ftp.size(remote_file)
except Exception as err:
# self.debug_print("is_same_size() 错误描述为:%s" % err)
remote_file_size = -1
try:
local_file_size = os.path.getsize(local_file)
except Exception as err:
# self.debug_print("is_same_size() 错误描述为:%s" % err)
local_file_size = -1
self.debug_print('local_file_size:%d , remote_file_size:%d' % (local_file_size, remote_file_size))
if remote_file_size == local_file_size:
return 1
else:
return 0
def download_file(self, local_file, remote_file):
"""从ftp下载文件
参数:
local_file: 本地文件
remote_file: 远程文件
"""
self.debug_print("download_file()---> local_path = %s ,remote_path = %s" % (local_file, remote_file))
if self.is_same_size(local_file, remote_file):
self.debug_print('%s 文件大小相同,无需下载' % local_file)
return
else:
try:
self.debug_print('>>>>>>>>>>>>下载文件 %s ... ...' % local_file)
buf_size = 1024
file_handler = open(local_file, 'wb')
self.ftp.retrbinary('RETR %s' % remote_file, file_handler.write, buf_size)
file_handler.close()
except Exception as err:
self.debug_print('下载文件出错,出现异常:%s ' % err)
return
def download_file_tree(self, local_path, remote_path):
"""从远程目录下载多个文件到本地目录
参数:
local_path: 本地路径
remote_path: 远程路径
"""
print("download_file_tree()---> local_path = %s ,remote_path = %s" % (local_path, remote_path))
try:
self.ftp.cwd(remote_path)
except Exception as err:
self.debug_print('远程目录%s不存在,继续...' % remote_path + " ,具体错误描述为:%s" % err)
return
if not os.path.isdir(local_path):
self.debug_print('本地目录%s不存在,先创建本地目录' % local_path)
os.makedirs(local_path)
self.debug_print('切换至目录: %s' % self.ftp.pwd())
self.file_list = []
# 方法回调
self.ftp.dir(self.get_file_list)
remote_names = self.file_list
self.debug_print('远程目录 列表: %s' % remote_names)
for item in remote_names:
file_type = item[0]
file_name = item[1]
local = os.path.join(local_path, file_name)
if file_type == 'd':
print("download_file_tree()---> 下载目录: %s" % file_name)
self.download_file_tree(local, file_name)
elif file_type == '-':
print("download_file()---> 下载文件: %s" % file_name)
self.download_file(local, file_name)
self.ftp.cwd("..")
self.debug_print('返回上层目录 %s' % self.ftp.pwd())
return True
def upload_file(self, local_file, remote_file):
"""从本地上传文件到ftp
参数:
local_path: 本地文件
remote_path: 远程文件
"""
if not os.path.isfile(local_file):
self.debug_print('%s 不存在' % local_file)
return
if self.is_same_size(local_file, remote_file):
self.debug_print('跳过相等的文件: %s' % local_file)
return
buf_size = 1024 * 64
file_handler = open(local_file, 'rb')
self.ftp.storbinary('STOR %s' % remote_file, file_handler, buf_size)
file_handler.close()
self.debug_print('上传: %s' % local_file + "成功!")
def upload_file_tree(self, local_path, remote_path):
"""从本地上传目录下多个文件到ftp
参数:
local_path: 本地路径
remote_path: 远程路径
"""
if not os.path.isdir(local_path):
self.debug_print('本地目录 %s 不存在' % local_path)
return
"""
创建服务器目录
"""
try:
self.ftp.cwd(remote_path) # 切换工作路径
except Exception as e:
base_dir, part_path = self.ftp.pwd(), remote_path.split('/')
for p in part_path[1:-1]:
base_dir = base_dir + p + '/' # 拼接子目录
try:
self.ftp.cwd(base_dir) # 切换到子目录, 不存在则异常
except Exception as e:
print('INFO:', e)
self.ftp.mkd(base_dir) # 不存在创建当前子目录
# self.ftp.cwd(remote_path)
self.debug_print('切换至远程目录: %s' % self.ftp.pwd())
local_name_list = os.listdir(local_path)
self.debug_print('本地目录list: %s' % local_name_list)
# self.debug_print('判断是否有服务器目录: %s' % os.path.isdir())
for local_name in local_name_list:
src = os.path.join(local_path, local_name)
print("src路径==========" + src)
if os.path.isdir(src):
try:
self.ftp.mkd(local_name)
except Exception as err:
self.debug_print("目录已存在 %s ,具体错误描述为:%s" % (local_name, err))
self.debug_print("upload_file_tree()---> 上传目录: %s" % local_name)
self.debug_print("upload_file_tree()---> 上传src目录: %s" % src)
self.upload_file_tree(src, local_name)
else:
self.debug_print("upload_file_tree()---> 上传文件: %s" % local_name)
self.upload_file(src, local_name)
self.ftp.cwd("..")
def upload_file_bytype(self, local_path, remote_path, type):
"""根据类型从本地上传目录下多个文件到ftp
参数:
local_path: 本地路径
remote_path: 远程路径
type:后缀类型
"""
if not os.path.isdir(local_path):
self.debug_print('本地目录 %s 不存在' % local_path)
return
"""
创建服务器目录
"""
try:
self.ftp.cwd(remote_path) # 切换工作路径
except Exception as e:
base_dir, part_path = self.ftp.pwd(), remote_path.split('/')
for p in part_path[1:-1]:
base_dir = base_dir + p + '/' # 拼接子目录
try:
self.ftp.cwd(base_dir) # 切换到子目录, 不存在则异常
except Exception as e:
print('INFO:', e)
self.ftp.mkd(base_dir) # 不存在创建当前子目录
# self.ftp.cwd(remote_path)
self.debug_print('切换至远程目录: %s' % self.ftp.pwd())
local_name_list = os.listdir(local_path)
self.debug_print('本地目录list: %s' % local_name_list)
# self.debug_print('判断是否有服务器目录: %s' % os.path.isdir())
for local_name in local_name_list:
src = os.path.join(local_path, local_name)
print("src路径==========" + src)
if os.path.isdir(src):
try:
self.ftp.mkd(local_name)
except Exception as err:
self.debug_print("目录已存在 %s ,具体错误描述为:%s" % (local_name, err))
self.debug_print("upload_file_tree()---> 上传目录: %s" % local_name)
self.debug_print("upload_file_tree()---> 上传src目录: %s" % src)
self.upload_file_tree(src, local_name)
else:
if local_name[len(local_name) - 3:len(local_name)] == type:
self.debug_print("upload_file_tree()---> 上传文件: %s" % local_name)
self.upload_file(src, local_name)
self.ftp.cwd("..")
def close(self):
""" 退出ftp
"""
self.debug_print("close()---> FTP退出")
self.ftp.quit()
self.log_file.close()
def debug_print(self, s):
""" 打印日志
"""
self.write_log(s)
def deal_error(self, e):
""" 处理错误异常
参数:
e:异常
"""
log_str = '发生错误: %s' % e
self.write_log(log_str)
sys.exit()
def write_log(self, log_str):
""" 记录日志
参数:
log_str:日志
"""
# time_now = time.localtime()
# date_now = time.strftime('%Y-%m-%d', time_now)
# format_log_str = "%s ---> %s \n " % (date_now, log_str)
format_log_str = log_str
print(format_log_str)
self.data.append(format_log_str)
self.v.set(self.data)
# 在最底部更新
self.listbox.see(END)
self.log_file.write(format_log_str)
def get_file_list(self, line):
""" 获取文件列表
参数:
line:
"""
file_arr = self.get_file_name(line)
# 去除 . 和 ..
if file_arr[1] not in ['.', '..']:
self.file_list.append(file_arr)
def get_file_name(self, line):
""" 获取文件名
参数:
line:
"""
pos = line.rfind(':')
while (line[pos] != ' '):
pos += 1
while (line[pos] == ' '):
pos += 1
file_arr = [line[0], line[pos:]]
return file_arr
def main():
MyFtpGUI()
mainloop()
if __name__ == "__main__":
main()
# my_ftp = MyFTP("192.168.1.106")
# my_ftp.set_pasv(False)
# my_ftp.login("admin", "123")
# 下载单个文件
# my_ftp.download_file("/home/BG_2019_05_22_16_04_54_Camera6-0.mp4", "/BG_2019_05_22_16_04_54_Camera6-0.mp4") #FTP服务器目录 本地目录
# 下载目录
# my_ftp.download_file_tree("G:/ftp_test/", "App/AutoUpload/ouyangpeng/I12/")
# 上传单个文件
# my_ftp.upload_file(r"C:\Users\91629\PycharmProjects\untitled1\ftp上传工具\test.jpg", "/1234141/new/test.jpg")
# 上传目录
# my_ftp.upload_file_tree(r"C:\Users\91629\Desktop\testd", "/1234141/")
# my_ftp.upload_file_bytype(r"C:\Users\91629\Desktop\testd", "/1234141/", "txt")
# my_ftp.close()
MysqlHelper.py
from click._compat import raw_input
from pymysql import *
"""封装mysql连接类"""
class MysqlHelper:
"""初始化数据库参数"""
def __init__(self, host, port, user, passwd, db, charset):
# 数据库连接地址
self.host = host
# 地址端口
self.port = port
# 数据库用户名
self.user = user
# 数据库密码
self.passwd = passwd
# 数据库名称
self.db = db
# 编码
self.charset = charset
"""连接数据库,获取Connection对象和cursor游标对象"""
def open(self):
self.conn = connect(host=self.host, port=self.port, user=self.user, passwd=self.passwd, db=self.db,
charset=self.charset)
self.cursor = self.conn.cursor()
"""执行用户输入的sql语句,参数化sql语句中的输入值"""
def execute(self, sql, params=()):
try:
# 打开数据库连接
self.open()
# 执行sql语句
self.cursor.execute(sql, params)
# 提交事务
self.conn.commit()
# 关闭数据库连接
self.close()
# print("sql执行完成")
except Exception as e:
# 发送错误回滚
# self.rollback()
return e
def createDataBase(self, sql, params=()):
try:
# 打开数据库连接
conn = connect(host=self.host, port=self.port, user=self.user, passwd=self.passwd,
charset=self.charset)
cursor = conn.cursor()
# 执行sql语句
cursor.execute(sql, params)
# 提交事务
conn.commit()
# 关闭数据库连接
cursor.close()
conn.close()
# print("sql执行完成")
except Exception as e:
# 发送错误回滚
# self.rollback()
print(e)
"""返回sql全部查询结果"""
def all(self, sql, params=()):
try:
# 打开数据库连接
self.open()
# 执行sql语句
self.cursor.execute(sql, params)
# 调用cursor的fetchall获取全部执行结果
result = self.cursor.fetchall()
# 关闭数据库连接
self.close()
# 返回执行结果
return result
except Exception as e:
return e
"""返回sql查询结果一行"""
def single(self, sql, params=()):
try:
# 打开数据库连接
self.open()
# 执行sql语句
self.cursor.execute(sql, params)
# 调用cursor的fetchone获取全部执行结果中的一条
result = self.cursor.fetchone()
# 关闭数据库连接
self.close()
# 返回执行结果
return result
except Exception as e:
print(e)
"""数据库回滚"""
def rollback(self):
self.conn.rollback()
"""关闭数据库"""
def close(self):
self.cursor.close()
self.conn.close()
"""测试用"""
if __name__ == '__main__':
msh = MysqlHelper('localhost', 8080, 'root', '123', 'test', 'utf8')
name = raw_input('请输入学生姓名:')
sbname = raw_input('请输入科目名称:')
sql = 'insert into students(name) values(%s)'
sql1 = 'insert into subjects(sbname) values(%s)'
sql2 = 'select id,name from students where id<5'
msh.execute(sql, [name])
msh.execute(sql1, [sbname])
print(msh.all(sql2))
上传功能部分代码来自http://blog.csdn.net/ouyang_peng/article/details/79271113
程序可能存在部分bug,欢迎交流指正。