author == ‘ljh’
from tkinter import *
制作GUI界面
import paramiko
用来远程
import time
from tqdm import tqdm
用来显示进程
import os
import threading
本打算调用多线程来完成更新文件,来达到更快的速度。但这样的话,需要将run函数查分成多个函数,如果数量多的话您可以自行考虑
class Application(Frame):
def init(self, master):
super(Application, self).init(master)
# 继承超类/父类的初始化
Label(self, text='Remote Data Dir').grid(row=0, column=0, sticky=W, padx=0, pady=0)
default_remote_dir = StringVar()
# 字符变量
default_remote_dir.set(r'/备站备份/')
self.remote_dir_ent = Entry(self, textvariable=default_remote_dir, width=52)
# width值是自己摸索的 grid()来布局需要自己重复的实验,以求找到最合适的大小
self.remote_dir_ent.grid(row=0, column=1, columnspan=3, sticky=W, padx=0, pady=0)
Label(self, text='Local Data Dir').grid(row=1, column=0, sticky=W, padx=0, pady=0)
default_local_dir = StringVar()
default_local_dir.set(r'D:\ljh\untitled\sdv')
self.local_dir_ent = Entry(self, textvariable=default_local_dir, width=52)
self.local_dir_ent.grid(row=1, column=1, columnspan=3, sticky=W, padx=0, pady=0)
Label(self, text='Remote IP').grid(row=2, column=0, sticky=W, padx=0, pady=0)
default_ip = StringVar()
default_ip.set('10.127.84.11')
self.ip_ent = Entry(self, textvariable=default_ip)
self.ip_ent.grid(row=2, column=1, sticky=W, padx=0, pady=0)
Label(self, text='Remote Port').grid(row=2, column=2, sticky=W, padx=0, pady=0)
default_port = IntVar()
default_port.set(22)
self.port_ent = Entry(self, textvariable=default_port)
self.port_ent.grid(row=2, column=3, padx=0, pady=0)
Label(self, text='Username').grid(row=3, column=0, sticky=W, padx=0, pady=0)
default_username = StringVar()
default_username.set('Backup')
self.username_ent = Entry(self, textvariable=default_username)
self.username_ent.grid(row=3, column=1, sticky=W, padx=0, pady=0)
Label(self, text='Password').grid(row=3, column=2, sticky=W, padx=0, pady=0)
default_password = StringVar()
default_password.set('re955426')
self.password_ent = Entry(self, textvariable=default_password, show='*')
self.password_ent.grid(row=3, column=3, padx=0, pady=0)
Label(self, text='time interval(h)').grid(row=4, column=0, sticky=W, padx=0, pady=0)
default_time_interval = IntVar()
default_time_interval.set(24)
self.time_interval_ent = Entry(self, textvariable=default_time_interval)
self.time_interval_ent.grid(row=4, column=1, sticky=W, padx=0, pady=0)
self.bttn = Button(self, text='Start ', command=self.run)
self.bttn.grid(row=5, rowspan=2, column=0, columnspan=2, sticky=W, padx=0, pady=0)
# 原本打算做出一个显示更新信息的文本,但不会异步更新。因此先放到一边
# self.txt = Text(self, wrap=WORD)
# self.txt.grid(row=5, rowspan=2, column=0, columnspan=4, padx=0, pady=0)
# self.scroll = Scrollbar(self, command=self.txt.yview, width=15)
# self.txt.configure(yscrollcommand=self.scroll.set)
# self.scroll.grid(row=5, rowspan=2, column=5, sticky=N+S)
self.grid()
def run(self):
ip = self.ip_ent.get()
port = self.port_ent.get()
port = int(port)
username = self.username_ent.get()
password = self.password_ent.get()
# 以上得到GUI中Entry中的输入值
transport = paramiko.Transport((ip, port))
transport.connect(username=username, password=password)
sftp = paramiko.SFTPClient.from_transport(transport)
# 连接远程sftp,并实例化一个远程会话
remote_source_dir = self.remote_dir_ent.get()
local_source_dir = self.local_dir_ent.get()
print('Running Update time: ' + str(time.ctime()))
while True:
# 用来定时更新,所以用的死循环
local_walks = os.walk(local_source_dir)
# 考虑到文件夹的递归问题即文件夹里还有文件夹,因此调用os.walk()a方法, 其返回一个迭代器,3维数组,第一个为
# 当前的目录,第二个为当前路径下的目录,第三个为当前目录下的文件名
year = time.localtime()[0]
month = time.localtime()[1]
day = time.localtime()[2]
today_files = '{:4}{:02}{:02}'.format(year, month, day)
# 此处构造了一个有关当天时间的字符串,因为我这边是不要更新今天生成的不完整的文件的
# (文件在第二天会在此有其他软件生成),这里的思想是构造你需要过滤的文件,在一次更新中不更新此类文件
local_walks = list(local_walks)
# 将迭代器变为列表,因为需要循环调用
for i in local_walks:
local_dirname = i[0]
dirs = i[1]
files = i[2]
# 此处的local_dirname、dirs、files就是上述os.walk()返回的3维数组的内容
dirname = i[0].replace(local_source_dir, '')
dirname = dirname.replace('\\', '')
# 此处得到递归的文件夹的名字,方便与远程的服务器中的地址构成新的目录,从而传输文件
if dirname != '':
remote_dirname = remote_source_dir + dirname + '/'
else:
remote_dirname = remote_source_dir + dirname
# 得到新的远程目录
for t in range(1):
try:
sftp.mkdir(remote_dirname)
print('Create remote dir: ' + remote_dirname + '!')
except:
continue
# 检查是否需要新建文件夹,因为sftp中我没有看到类似于os.path.isdir()的方法,因此考虑用try来解决
# for循环是为了配合continue
remote_source_dirs = sftp.listdir(remote_dirname)
# 得到远程服务器下当前目录下的文件和目录列表
transport_files = set(files) - set(remote_source_dirs)
transport_files = list(transport_files)
# 利用集合的相减得到要更新的文件。注意此处是单纯的文件。
for j in transport_files:
if today_files in j:
transport_files.remove(j)
elif j in dirs:
transport_files.remove(j)
# 此处为过滤不需要更新的文件,elif部分可以考虑不要
for j in tqdm(transport_files, bar_format='{l_bar}{bar}'):
# 方法tqdm可以显示更新的进度
file_path = local_dirname + '\\' + str(j)
remote_file_path = remote_dirname + str(j)
# 构造本地和远程的文件的路径
sftp.put(file_path, remote_file_path)
# 将文件从本地上传到服务器
print('Remote directory: ' + remote_dirname + '\'s updating is completed!')
interval = self.time_interval_ent.get()
interval = int(interval)
# get()得到的是字符串,因此强制转换成整型
time.sleep(interval // 4)
# 设置休眠时间
print('Running Update time: ' + str(time.ctime()))
if name == ‘main‘:
root = Tk()
root.title(‘SFTP_数据备份’)
root.geometry(‘475x160’)
app = Application(root)
root.mainloop()