之前写了一个同步的脚本 同步文件小工具_sync (python实现),觉得还挺好用。有个问题就是,它只能在安装了python的电脑上使用。但是我觉得身边其他没学过python的朋友估计也会用上,所以就把它打包了。时间有限,只用简单的tkinter实现,界面有点丑,花了2个小时从原来的脚本改过来。
本着开源的原则,文末会给上所有代码。也希望前端大佬可以包装得好看点。
【注意】请不要将此软件用于商业或者其他盈利性用途。
设备要求: windows 64位
(不需要额外装任何东西
用途:
- 检测到没有改动的文件则不会进行 *** 作,该功能对有很多未改动的大文件的目录可以省下很多时间。
(注意: 判断条件是使用修改时间,所以如果您第一次是直接复制的话,修改时间是不一样的,所以会造成程序第一次执行分析比较的时候,认为二者是不同的。但是只要您执行完一次确定同步后,下一次分析比较就是相同了。这一点需要留意。
目前存在缺点:
- 提示信息不够美观,界面不够美观
- 启动较慢,需要几秒
- 只适用于win 64位机子,虽然现在大多数机子也是win64。
- 执行较多文件 *** 作中途有点卡顿,开始执行文件时会出现短暂的未响应(1~2秒)。
- exe文件大小86.2M, 有点大…
- 执行结果输出需要自己滑动鼠标查看被遮挡的输出(滚动条隐藏了)
下载地址
- synctools.exe (gitee)
放在gitee是因为gitee服务器在国内,下载快,大概校园网可以到1m/s左右, 所以会下个一分多钟就好了。
先 【选择原始目录】,
然后 【选择目标目录】。
就可以 【分析比较】,
然后如果要同步则 【确定同步】,由于是不可逆 *** 作,这里还会d出一个框询问您是否确定同步。
# -*- coding: UTF-8 -*- """ syncTools GUI windows版本 @ Author: Andy Dennis @ Date: 2021.12.20 @ Detail: V1.0 可以实现 windows 64位机器的两个目录下 所有目录和文件 的同步。 参考代码: https://blog.csdn.net/weixin_43850253/article/details/121276204 """ import shutil import os from tqdm import tqdm import time import tkinter as tk from tkinter import filedialog, messagebox import tkinter.font as tf import webbrowser class SyncTools: def __init__(self, text_edit): self.text_edit = text_edit # 输出信息的框 self.compare_status = False # 设置compare状态 def set_compare_status(self, status:bool): self.compare_status = status # 返回compare状态 def get_compare_status(self): return self.compare_status # 比较目录 def compare_operation(self, d_a:str, d_b:str): """ 同步目录: d_a -> d_b """ self.add_dir_lt = [] # 增加的目录列表 self.del_dir_lt = [] # 删除的目录列表 self.add_file_lt = [] # 增加的文件列表 self.edit_file_lt = [] # 修改的文件列表 self.del_file_lt = [] # 删除的文件列表 self.dir_origin = d_a # 原始目录 self.dir_target = d_b # 目标目录 self.same_flag = True # 两个目录是否相同 start_compare_time = time.time() self.compare_directory(d_a=d_a, d_b=d_b) end_compare_time = time.time() self.text_edit_add('---> 比较目录时长花费: {} 秒n'.format(round(end_compare_time - start_compare_time, 3))) if len(self.add_dir_lt) == 0 and len(self.del_dir_lt) == 0 and len(self.add_file_lt) == 0 and len(self.del_file_lt) == 0 and len(self.edit_file_lt) == 0: self.text_edit_add(' 两个目录已经是相同的啦, 您不需要再进行 *** 作~~~') else: self.show_tip() self.set_compare_status(True) # 执行同步 *** 作 def sync_operation(self): """ 同步目录: d_a -> d_b """ if len(self.add_dir_lt) == 0 and len(self.del_dir_lt) == 0 and len(self.add_file_lt) == 0 and len(self.del_file_lt) == 0 and len(self.edit_file_lt) == 0: self.text_edit_add(' 两个目录已经是相同的啦, 您不需要再进行同步~~~') return start_op_time = time.time() self.start_operation() end_op_time = time.time() self.text_edit_add('---> 执行 *** 作花费: {} 秒'.format(round(end_op_time - start_op_time, 3))) self.set_compare_status(False) # 比较目录差别, 并存储下来需要的 *** 作 def compare_directory(self, d_a:str, d_b:str): d_a_set = set(os.listdir(d_a)) d_b_set = set(os.listdir(d_b)) # a目录比 b 目录多的, 目录 b 待添加项 d_a_more_item_lt = [] # b目录比 a 目录多的 d_a_more_item_lt = [] # 相同的部分需要比较文件大小等, 有可能进行了修改 path_same_item_lt = [] d_a_more_item_lt = list(d_a_set - d_b_set) d_b_more_item_lt = list(d_b_set - d_a_set) path_same_item_lt = list(d_a_set & d_b_set) # 处理 a 目录多的 for item in d_a_more_item_lt: item_path = '{}/{}'.format(d_a, item) if os.path.isdir(item_path): # 如果是目录, 那么无疑该目录下的所有文件都是要添加的 self.add_dir_lt.append(item_path.replace(self.dir_origin, self.dir_target)) self.add_all_director_item(item_path, True) else: self.add_file_lt.append(item_path) # 处理 b 目录多的 for item in d_b_more_item_lt: item_path = '{}/{}'.format(d_b, item) if os.path.isdir(item_path): # 如果是目录, 那么无疑该目录下的所有文件都是要添加的 self.del_dir_lt.append(item_path) self.add_all_director_item(item_path, False) else: self.del_file_lt.append(item_path) # 处理一样的 for item in path_same_item_lt: item_a_path = '{}/{}'.format(d_a, item) item_b_path = '{}/{}'.format(d_b, item) if os.path.isdir(item_a_path): # 如果是目录, 那么递归处理 self.compare_directory(d_a=item_a_path, d_b=item_b_path) else: time_a = os.path.getmtime(item_a_path) time_b = os.path.getmtime(item_b_path) if os.path.getsize(item_a_path) == os.path.getsize(item_b_path) and abs(time_a - time_b) <= 2: # 两个文件一样大, 如果修改时间相差小于2秒 pass else: self.edit_file_lt.append([item_a_path, item_b_path]) # 将该目录下的所有目录和文件添加到待创建和待复制的任务列表中 def add_all_director_item(self, dir_path:str, is_add:bool): for item in os.listdir(dir_path): item_path = '{}/{}'.format(dir_path, item) if os.path.isdir(item_path): if is_add: self.add_dir_lt.append(item_path.replace(self.dir_origin, self.dir_target)) self.add_all_director_item(item_path, is_add) else: if is_add: self.add_file_lt.append(item_path) else: self.del_file_lt.append(item_path) # 展示即将要进行的操作以及询问是否继续 def show_tip(self): self.text_edit_add('原始目录: {}'.format(self.dir_origin)) self.text_edit_add('目标目录: {}'.format(self.dir_target)) self.text_edit_add('n 点击确定同步后 目标目录 将与 原始目录一样n') self.print_operation_lt(self.add_dir_lt, '要创建的目录') self.print_operation_lt(self.del_dir_lt, '要删除的目录') self.print_operation_lt(self.add_file_lt, '要复制的文件') self.print_operation_lt(self.del_file_lt, '要删除的文件') self.print_operation_lt(self.edit_file_lt, '要修改的文件') # 更好的打印项目提示 def print_operation_lt(self, lt:list, tip:str): if len(lt) > 0: self.text_edit_add(' {} '.format(tip).center(50, '-')) for item in lt: if isinstance(item , list): # 修改文件 self.text_edit_add(' {} -> {}'.format(item[0], item[1])) else: self.text_edit_add('{}{}'.format(' ' * 4, item)) self.text_edit_add('') # 开始执行 *** 作 def start_operation(self): self.text_edit_add('n ^_^开始 *** 作...') if len(self.add_dir_lt) > 0: self.text_edit_add('正在创建目录...') for item in self.add_dir_lt: os.makedirs(item) self.text_edit_add('') if len(self.add_file_lt) > 0: self.text_edit_add('正在复制文件...') for item in self.add_file_lt: item_target = item.replace(self.dir_origin, self.dir_target) shutil.copyfile(item, item_target) # 设置文件的访问时间和修改时间 self.set_a_m_time(item, item_target) self.text_edit_add('copy {} done'.format(item.split('/')[-1])) self.text_edit_add('') if len(self.del_file_lt) > 0: self.text_edit_add('正在删除文件...') for item in self.del_file_lt: os.remove(item) self.text_edit_add('delete {} done'.format(item.split('/')[-1])) self.text_edit_add('') if len(self.edit_file_lt) > 0: self.text_edit_add('正在修改文件...') for item in self.edit_file_lt: os.remove(item[1]) shutil.copyfile(item[0], item[1]) # 设置文件的访问时间和修改时间 self.set_a_m_time(item[0], item[1]) self.text_edit_add('edit {} done'.format(item[0].split('/')[-1])) self.text_edit_add('') if len(self.del_dir_lt) > 0: self.text_edit_add('正在删除目录...') for item in self.del_dir_lt: shutil.rmtree(item) self.text_edit_add(' 执行结束 done!') # 设置文件的访问时间和修改时间 def set_a_m_time(self, item_o, item_t): # 设置它们的修改时间一样 st_item_o = os.stat(item_o) os.utime(item_t, (st_item_o.st_atime, st_item_o.st_mtime)) # 输出框添加输出内容 def text_edit_add(self, text_str, newline=True): if newline: text_str += 'n' self.text_edit.insert('end', text_str) # 选择原始目录 def select_origin_dir(): global origin_dir global target_dir fp = filedialog.askdirectory(title=u'选择原始目录') try: if fp is not None and len(fp) > 0: origin_dir = fp # print('origin_dir: ', origin_dir) text_edit.delete('1.0','end') text_edit.insert('end', 'origin_dir: {}n'.format(origin_dir)) if len(target_dir) > 0: text_edit.insert('end', 'target_dir: {}n'.format(target_dir)) # tk.messagebox.showinfo('success', '选择原始目录成功') else: tk.messagebox.showerror('error', '选择原始目录失败') except: tk.messagebox.showerror('error', '选择原始目录失败') # 选择目标目录 def select_target_dir(): global target_dir global origin_dir if len(origin_dir) == 0: tk.messagebox.showerror('error', '请选择好原始目录') return fp = filedialog.askdirectory(title=u'选择目标目录') try: if fp is not None and len(fp) > 0: target_dir = fp # print('target_dir: ', target_dir) text_edit.delete('1.0','end') text_edit.insert('end', 'origin_dir: {}n'.format(origin_dir)) text_edit.insert('end', 'target_dir: {}n'.format(target_dir)) # tk.messagebox.showinfo('success', '选择目标目录成功') else: tk.messagebox.showerror('error', '选择目标目录失败') except: tk.messagebox.showerror('error', '选择目标目录失败') # 比较两个目录之间的差别 def compare_dir(): global origin_dir global target_dir global sync_tool if len(origin_dir) == 0 or len(target_dir) == 0: tk.messagebox.showerror('error', '请选择好原始和目标目录') return sync_tool.compare_operation(origin_dir, target_dir) # 执行同步 *** 作 def sync_operation(): global origin_dir global target_dir global sync_tool if len(origin_dir) == 0 or len(target_dir) == 0: tk.messagebox.showerror('error', '请选择好原始和目标目录') return if sync_tool.get_compare_status() is None or sync_tool.get_compare_status() == False: tk.messagebox.showerror('error', '请先点击比较目录按钮') return if tk.messagebox.askyesno('Verify', 'Do you really want to sync?'): sync_tool.sync_operation() # 取消同步 *** 作 def cancel(): global origin_dir global target_dir global sync_tool origin_dir = '' target_dir = '' # 清除输出框所有内容 text_edit.delete('1.0','end') sync_tool.set_compare_status(False) # 此处必须注意,绑定的事件函数中必须要包含event参数 def open_url(event): webbrowser.open("https://blog.csdn.net/weixin_43850253/article/details/122056874", new=0) window = tk.Tk() # 标题 window.title('sync tools 简易同步小软件 v1.0') # 窗口尺寸 window.geometry('504x470') # 不允许重新设置大小 window.resizable('false', 'false') # 设置背景颜色 window['background'] = '#90d7ec' # 全局目录 origin_dir = '' target_dir = '' bt1 = tk.Button(window, text='选择原始目录', width=16, height=1, font=tf.Font(size=12), command=select_origin_dir) bt1.place(x=30, y=30) bt2 = tk.Button(window, text='选择目标目录', width=16, height=1, font=tf.Font(size=12), command=select_target_dir) bt2.place(x=330, y=30) text_edit = tk.Text(window, width=60, height=20, bg='bisque', font=tf.Font(size=12), fg='blue') text_edit.place(x=10, y=80) sync_tool = SyncTools(text_edit) bt3 = tk.Button(window, text='分析比较', width=12, height=1, font=tf.Font(size=12), command=compare_dir) bt3.place(x=30, y=420) bt4 = tk.Button(window, text='确定同步', width=12, height=1, font=tf.Font(size=12), command=sync_operation) bt4.place(x=190, y=420) bt5 = tk.Button(window, text='取消执行', width=12, height=1, font=tf.Font(size=12), command=cancel) bt5.place(x=344, y=420) lb1 = tk.Label(window, text='点我获取帮助', font=tf.Font(size=10), fg='purple', background='#90d7ec') lb1.place(x=410, y=450) lb1.bind("", open_url) window.mainloop()
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)