Python编写的简易文件同步工具(已解决大文件同步时内存溢出问题)

个人工作时,会出现有两台或多台电脑需要同步一些文件的情况,但是因为公司文档的私密性,又不能上传网盘,就算有群晖,但是一直开着检测目录变化的功能,又有点浪费电脑性能,所以就用python写了如下的小脚本,方便同步数据,因为系统占用很低,让它一直开着后台运行,也不至于影响工作,如果目标目录已有一样的文件也能很好的跳过,至于同步大文件时,内存泄漏问题,我也通过使用python的yield循环每次读取很小的部分(1024*8)解决了,还有因为有时文件比较多,一下同步不好,可以先中断,下次继续同步。废话不多说,看下面的的代码。

#作者:donglxd
#csdn博客:https://blog.csdn.net/donglxd?spm=1010.2135.3001.5421
#github:https://github.com/donglxd?tab=repositories

import os
import hashlib
import tkinter as tk
from tkinter import messagebox
import time
import sys
import keyboard
import threading

errmsg = ""
dfilename = ""
gotoBreak = False
stop_copying = False
finishexit = False

def chunked_file_Next_reader(file,block_size=1024 * 8):#分段读取比较的文件
    while True:
        global gotoBreak
        if gotoBreak:
            break
        yield file.read(block_size)

def copy_file(src, dst):#分段复制文件,可随时中断(stop_copying变量控制)
    global stop_copying
    with open(src, 'rb') as fs:
        with open(dst, 'wb') as fd:
            if stop_copying:
                print("stoped")
            while not stop_copying:
                buf = fs.read(1024)
                if not buf:
                    break
                fd.write(buf)
            fd.close()
        fs.close()

def md5_diff(sfile,dfile):#比较函数
    oldtime = time.time()
    count = 0
    scount = 0
    k = True
    with open(sfile,'rb') as sf:
        with open(dfile,'rb') as df:
            sdata = chunked_file_Next_reader(sf)
            fdata = chunked_file_Next_reader(df)
            while k:
                s_nxtdata = next(sdata)
                d_nxtdata = next(fdata)
                count += 1
                if s_nxtdata == b'':
                    if d_nxtdata == b'':
                        k = False
                    else:
                        count += 1
                        break
                else:
                    s_md5 = hashlib.md5(s_nxtdata).hexdigest()#分段比较每段的hash值
                    d_md5 = hashlib.md5(d_nxtdata).hexdigest()
                    if s_md5 == d_md5:
                        scount += 1        
                    else:
                        #判断文件不一样
                        sf.close()
                        df.close()
                        return 0
            if (count - 1) == scount:
                #判断文件一样
                sf.close()
                df.close()
                return 1
            else:
                #判断文件不一样
                sf.close()
                df.close()
                return 0

def check_keyborad():#子线程判断退出操作(按q退出)
    while True:
        if keyboard.is_pressed("q"):
            global errmsg
            global gotoBreak
            global stop_copying
            gotoBreak = True#设置退出比较函数
            stop_copying = True#设置退出复制函数
            if errmsg == "":
                errmsg = dfilename + " 处中断!"#设置断点断续的提示信息
                print("error:" + errmsg)
            with open(sys.path[0] + "\断点断续.txt",'w') as log:#把断点断续的位置写入与此脚本相同目录的"断点断续.txt"
                log.write(errmsg)
                log.close
            messagebox.showinfo("提示",errmsg)#t弹出断点断续的提示信息窗口
            sys.exit(0)
        time.sleep(0.2)
        if finishexit:
            break



def copyFile(spath,dpath):#判断复制主程序
    global dfilename
    for filename in os.listdir(spath):
        if gotoBreak:
            print("----------已中断-----------")
            break

        sfilename = spath + os.sep + filename
        dfilename = dpath + os.sep + filename
        dfilename = dfilename.replace('"',"")#替换掉拖到目标目录字符串中的引号
        sfilename = sfilename.replace('"',"")#替换掉拖到源目录字符串中的引号
    
        if os.path.isdir(sfilename):
            if not os.path.exists(dfilename):
                os.mkdir(dfilename)
            copyFile(sfilename,dfilename)
        else:
            global k

            if dfilename == xpath and k == False:#判断输入的目录是否为空,进入断点断续程序
                k = True
                print("断点断续开始位置:" + dfilename)
            if xpath == "" and k == False:#进入全新的同步进程
                k = True
                print("新开始:")    
            if k == True:
                if os.path.exists(dfilename):
                    ret = md5_diff(sfilename,dfilename)
                    if ret == 1:
                        errmsg = dfilename + " 处中断!"
                        #print('{} 文件已存在!'.format(dfilename))
                    else:
                        copy_file(sfilename,dfilename)
                        print('{} 文件已更新!'.format(dfilename))
                else:
                    print('{0} 复制到 {1}'.format(sfilename,dfilename))
                    copy_file(sfilename,dfilename)

def start():#主程序
    oldtime = time.time()
    t = threading.Thread(target=check_keyborad)#开启一个退出键盘子线程
    t.start()
    copyFile(spath,dpath)#判断复制文件主程序
    root = tk.Tk()
    root.withdraw()#隐藏主窗体
    newtime = time.time()
    if newtime - oldtime < 60:
        messagebox.showinfo("提示","文件夹已同步成功! 共用时: " + str(newtime - oldtime) + "秒!")    
    else:
        messagebox.showinfo("提示","文件夹已同步成功! 共用时: " + str((newtime - oldtime)/60) + "分钟!")
    global finishexit
    finishexit = True
    t.join()

if __name__ == "__main__":

    #---------初始化需同步的目录-----------
    #源目录
    spath = input("请输入源目录(如:E:\工作开发):")
    #spath = spath.replace('"',"")
    
    #目标目录
    dpath = input("请输入目标目录(如:Z:\\):")
    #spath = spath.replace('"',"")
    
    #断点断续位置给xpath变量赋值或xpath = ""赋空值来重新开始
    xpath = input("请输入之前中断的文件路径(如:X:\\1.txt),默认不使用断点断续直接按回车:")

    #--------------自动同步---------------
    #如需源目录\目标目录不变可以设定下面的值,并把上面的input代码注释掉.
    #spath = r"E:\工作开发"
    #dpath = "Z:\\"
    #xpath = ""
    
    k = False
    errmsg = ""

    #运行主程序
    start()

本脚本采用hash md5方式,分小区块,比较源文件夹和目标文件夹之前的差异并同步复制,只支持源文件夹到目标文件夹单向同步,并编写了判断键盘退出快捷键Q的子线程,提高退出时的速度。同时提供了断点断续功能,按q退出后,会弹出一个对话框提示同步中断位置,在此脚本保存的同目录,写入一个保存断点处文件路径的txt文件,方便下次从断点处恢复同步使用。因为分小区块比较和复制,所以可以解决超大文件内存溢出和按快捷键不能及时退出的问题。此脚本分为手动和自动设置源目文件夹路径,手动直接运行脚本,把源文件夹和目标文件夹拖动到命令行或终端窗口;如每次同步文件夹相同,可以设置自动模式,把脚本最下面的"自动同步"处的注释去掉并填入源目文件夹(源:spath;目:dpath),只是每次都要设置新的断点断续路径(xpath)或者不使用断点断续功能。

说下使用的方法,把上面的代码保存到新建一个.py的python文件,然后运行,会提示输入源文件目录(即原始文件夹),目标文件目录(即需同步到的文件夹),还有断点断续文件夹目录,如果你之前按q中断过程序,可以使用此功能。如果还是不懂如何使用请看下面的视频。

自编python小区块文件夹同步工具

如果不知道怎么创建py脚本,可以用我上传的。

csdn链接:https://download.csdn.net/download/donglxd/87928907

github链接:https://github.com/donglxd/syncFile

github博客主页:https://donglxd.github.io/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

虫鸣@蝶舞

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值