利用paramiko、tkinter、os等模块实现远程连接sftp,并进行文件夹的递归式定时传输

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()

猜你喜欢

转载自blog.csdn.net/ljh_csdn_ljh/article/details/80041306
今日推荐