用pyqt5写一个同步文件夹内容的小工具

详见https://github.com/distiny-cool/File-Synchronization
完整代码在最下面

同步文件夹内容的小工具【点这里直接下载可执行程序

出发点

打算把电脑上的文件备份到外部磁盘上面,但是原来已经备份过了,现在又有所修改,重新复制的话实在太慢,而且有的文件内容更新过了,有冲突时不能直接跳过,所以用pyqt5写了这个小程序用于解决这个问题。

思路

代码注释详细,可以自己修改,也可以供初学者学习pyqt5参考

from PyQt5.QtWidgets import QApplication, QDialog, QLabel, QLineEdit, QPushButton, QMessageBox, QFileDialog, QTextEdit, QHBoxLayout, QVBoxLayout, QWhatsThis
from PyQt5.QtGui import QIcon, QPixmap
from PyQt5.QtCore import QEvent
import shutil
import os
import sys
import ctypes

class SyncFilesWindow(QDialog):
    def __init__(self):
        super().__init__()
        filename = self.resource_path(os.path.join("ico","icon.ico"))
        icon = QIcon()
        icon.addPixmap(QPixmap(filename), QIcon.Normal, QIcon.Off)
        self.setWindowIcon(icon)
        ctypes.windll.shell32.SetCurrentProcessExplicitAppUserModelID("myappid")

        # 创建文本标签和文本框
        self.src_label = QLabel("源文件夹路径:", self)
        self.src_edit = QLineEdit(self)
        self.src_button = QPushButton("选择文件夹", self)
        self.dst_label = QLabel("目标文件夹路径:", self)
        self.dst_edit = QLineEdit(self)
        self.dst_button = QPushButton("选择文件夹", self)

        # 创建文本框用于显示同步的文件名称
        self.log_edit = QTextEdit(self)

        # 创建按钮
        self.sync_button = QPushButton("同步文件", self)

        # 创建水平布局,用于放置文本框和按钮
        hbox_src = QHBoxLayout()
        hbox_src.addWidget(self.src_edit)
        hbox_src.addWidget(self.src_button)
        hbox_dst = QHBoxLayout()
        hbox_dst.addWidget(self.dst_edit)
        hbox_dst.addWidget(self.dst_button)

        # 创建垂直布局
        vbox = QVBoxLayout()
        vbox.addWidget(self.src_label)
        vbox.addLayout(hbox_src)
        vbox.addWidget(self.dst_label)
        vbox.addLayout(hbox_dst)
        vbox.addWidget(self.sync_button)
        vbox.addWidget(self.log_edit)

        # 设置布局
        self.setLayout(vbox)

        # 连接按钮的点击事件和处理函数
        self.src_button.clicked.connect(self.select_src_dir)
        self.dst_button.clicked.connect(self.select_dst_dir)
        self.sync_button.clicked.connect(self.sync_files)

        # 设置窗口的属性
        self.setGeometry(300, 300, 420, 420)
        self.setWindowTitle('文件夹同步工具')

        self.infomation()

    def event(self, event):
        if event.type()==QEvent.EnterWhatsThisMode:
            QWhatsThis.leaveWhatsThisMode()
            QMessageBox.information(self, "关于", "开发:Kody Black\n"+
            "github.com/distiny-cool/File-Synchronization")
        return QDialog.event(self,event)


    def resource_path(self, relative_path):
        if getattr(sys, 'frozen', False): 
            base_path = sys._MEIPASS
        else:
            base_path = os.path.abspath(".")
        return os.path.join(base_path, relative_path)

    def select_src_dir(self):
        # 调用 QFileDialog.getExistingDirectory() 函数弹出文件夹选择对话框
        src_dir = QFileDialog.getExistingDirectory(self, "选择源文件夹")
        # 如果用户选择了文件夹,则在文本框中显示文件夹路径
        if src_dir:
            self.src_edit.setText(src_dir)

    def select_dst_dir(self):
        # 调用 QFileDialog.getExistingDirectory() 函数弹出文件夹选择对话框
        dst_dir = QFileDialog.getExistingDirectory(self, "选择目标文件夹")
        # 如果用户选择了文件夹,则在文本框中显示文件夹路径
        if dst_dir:
            self.dst_edit.setText(dst_dir)

    def infomation(self):
        self.log_edit.append('<font color="#0078d4"><b>功能介绍:</b></font>'+'<p>'+
        '本软件会把源文件夹和目标文件夹中不同的内容复制到目标文件夹里,完全相同的文件则直接跳过,以节省你的复制时间'+'<p>'+
        '<font color="#d83b01"><b>注意:</b></font><ul><li>目标文件夹不允许是源文件夹的子文件夹</li>'+
        '<li>如果有相同的文件,则在目标文件夹中会保留最近修改过的文件</li></ul>'+
        '<p style="text-align: right;"><font color="#6e9bc5">'+'<b> by:Kody </b></font></p>')

    def sync_files(self):
        # 获取文本框中的路径
        src_dir = self.src_edit.text()
        dst_dir = self.dst_edit.text()

        self.log_edit.clear()

        if not os.path.exists(src_dir):
            QMessageBox.warning(self, "错误", "源文件夹不存在!")
            return

        if not os.path.exists(dst_dir):
            QMessageBox.warning(self, "错误", "目标文件夹不存在!")
            return
        
        # 递归同步文件夹和文件
        def sync_files(src_dir, dst_dir) -> int:

            # 如果目标文件夹不存在,则创建目标文件夹
            if not os.path.exists(dst_dir):
                os.makedirs(dst_dir)
            
            # 遍历源文件夹中的文件
            for src_path in os.listdir(src_dir):
                src_path = os.path.join(src_dir, src_path)
                dst_path = os.path.join(dst_dir, src_path.split(os.sep)[-1])

                # 如果是文件夹,则递归处理
                if os.path.isdir(src_path):
                    sync_files(src_path, dst_path)
                # 如果是文件,则复制文件
                else:
                    # 如果文件已经存在,则比较时间戳
                    if os.path.exists(dst_path):
                        # 获取文件的时间戳
                        src_mtime = os.path.getmtime(src_path)
                        dst_mtime = os.path.getmtime(dst_path)

                        # 如果源文件的时间戳更新,则复制文件
                        if src_mtime > dst_mtime:
                            self.log_edit.append("正在复制文件: " + src_path)
                            shutil.copy2(src_path, dst_path)
                    else:
                        # 将文件复制到目标文件夹
                        self.log_edit.append("正在复制文件: " + src_path)
                        shutil.copy2(src_path, dst_path)
            return 1

        # 调用递归函数同步文件
        if sync_files(src_dir, dst_dir):
            QMessageBox.information(self, "提示", "文件同步成功!")
        else:
            QMessageBox.critical(self, "错误", "文件同步失败!")


if __name__ == '__main__':
    app = QApplication(sys.argv)
    window = SyncFilesWindow()
    window.show()
    sys.exit(app.exec_())

⭐️欢迎star&关注

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值