IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Python知识库 -> 同步文件小工具_sync (python实现) -> 正文阅读

[Python知识库]同步文件小工具_sync (python实现)

前言

我们的一些数据很珍贵,比如实验处理的中间结果,比如一些编辑的文件。
有时候我们会备份到不止一个地方(比如我,会备份到不同的u盘或者移动硬盘),但我们有可能某个时间段在某一份更改了好多次操作,我们自己也不知道改了哪些,这时候如果想备份的话有两种方法。第一,一个地方一个地方找,更要命的是多个备份的地方都要改。第二种方法是把旧的删了,新的重新复制,虽然简单粗暴,但是单文件很多很大时,更改的又不是很多,那么这样子每次都复制这么多个文件明显划不来。
(另外,大文件情况下,git就不是特别好用,传到云端备份再回来网速不好就很难受。

正是有这样想法, 让我想要写一个可以同步两个目录的程序。
基于Python,但是目前有个缺点就是是单线程的,可能今后有空想想怎么异步优化其性能。

使用一定要注意,是a -> b, 别反过来 !!! (不然会把旧版本目录覆盖掉新版本目录



代码

"""
大文件以及包含大文件的目录重命名建议直接手动操作
因为本代码只要名字不同都认为是不同的文件,没有做内容比较的优化
a -> b, 由 a 目录向 b 目录备份
Author:   Andy Dennis AIron
Date:     2021.11.11
Version:  V3.0
Detail:   相比V2.0, 修复exFAT格式文件系统时间戳精度问题。(line 84 判断条件)
判断文件是否相同方法: 文件大小和修改时间戳区别是否大于2秒, 所以请您修改完文件选择保存
的时间 与 上一次修改文件的时间(备份时的那个版本的文件)大于2秒即可
"""
import shutil
import os
from tqdm import tqdm


class Sync:
    def __init__(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.compare_directory(d_a=d_a, d_b=d_b)
        flag = self.show_tip_ask()    # 显示操作并询问是否继续
        if flag == 'yes':
            self.start_operation()
        elif flag == 'useless':
            print(' 两个目录已经是相同的啦, 您不需要再进行操作~~~')
        else:
            print('您取消了操作...')


    # 比较目录差别
    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_ask(self):
        print('原始目录: ', self.dir_origin)
        print('目标目录: ', self.dir_target)
        
        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:
            return 'useless'   # 没有必要更新, 两个目录相同
        print('执行完操作后 目标目录 将与 原始目录一样\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, '要修改的文件')

        choice = input('请您仔细查看后,确认是否继续操作(y/n)')
        if choice.isalpha() and choice.lower() == 'y':
            return 'yes'
        return 'false'
        

    # 更好的打印项目提示
    def print_operation_lt(self, lt:list, tip:str):
        if len(lt) > 0:
            print(' {} '.format(tip).center(50, '-'))
            for item in lt:
                if isinstance(item , list): # 修改文件
                    print(' {} -> {}'.format(item[0], item[1]))
                else:
                    print(' ' * 4, item)
            print()


    # 开始执行操作
    def start_operation(self):
        print('\n ^_^开始操作...')

        if len(self.add_dir_lt) > 0:
            print('正在创建目录...')
            for item in tqdm(self.add_dir_lt):
                os.makedirs(item)
            print()

        
        if len(self.add_file_lt) > 0:
            print('正在复制文件...')
            for item in tqdm(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)
            print()
        
        if len(self.del_file_lt) > 0:
            print('正在删除文件...')
            for item in tqdm(self.del_file_lt):
                os.remove(item)
            print()

        if len(self.edit_file_lt) > 0:
            print('正在修改文件...')
            for item in tqdm(self.edit_file_lt):
                os.remove(item[1])
                shutil.copyfile(item[0], item[1])
                # 设置文件的访问时间和修改时间
                self.set_a_m_time(item[0], item[1])
            print()

        if len(self.del_dir_lt) > 0:
            print('正在删除目录...')
            for item in tqdm(self.del_dir_lt):
                shutil.rmtree(item)
        print(' 执行结束 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))


if __name__ == '__main__':
    # 想要被备份的目录
    d1 = 'C:/Users/Administrator/Desktop/sync/a'
    # d1 = 'C:/Users/Administrator/Desktop/test'

    # 想备份到的目标目录 (注意d2目录会被覆盖)
    d2 =  'C:/Users/Administrator/Desktop/sync/b'
    # d2 =  'C:/Users/Administrator/Desktop/sync/c'


    # 开始操作
    _ = Sync(d1, d2)



效果

先来一个简单的实验
在这里插入图片描述


再来一个复杂一点的
在这里插入图片描述
在这里插入图片描述

如果路径一样:
在这里插入图片描述

  Python知识库 最新文章
Python中String模块
【Python】 14-CVS文件操作
python的panda库读写文件
使用Nordic的nrf52840实现蓝牙DFU过程
【Python学习记录】numpy数组用法整理
Python学习笔记
python字符串和列表
python如何从txt文件中解析出有效的数据
Python编程从入门到实践自学/3.1-3.2
python变量
上一篇文章      下一篇文章      查看所有文章
加:2021-11-12 19:32:52  更:2021-11-12 19:34:59 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/15 23:47:36-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码