作为一名用户,你是否也曾为Windows命令行工具的复杂性而头疼?尤其是Robocopy这样功能强大但使用门槛较高的工具。今天,我将分享如何使用PyQt5将Robocopy打造成一个直观易用的图形界面工具,让文件复制任务变得简单高效。

项目背景与目标
Robocopy(Robust File Copy)是Windows系统自带的命令行文件复制工具,功能强大但使用复杂,需要记忆大量命令参数。作为程序员小白,我决定开发一个可视化界面,降低使用门槛,同时保留Robocopy的强大功能。
项目目标:
-
提供直观的图形界面,无需记忆命令参数
-
保留Robocopy的全部核心功能
-
优化用户体验,符合现代UI设计标准
-
支持中文显示和操作
技术选型与架构设计
为什么选择PyQt5?
在众多GUI框架中,我选择了PyQt5,主要考虑以下因素:
-
跨平台性:可在Windows、macOS和Linux上运行
-
功能完备:提供丰富的UI组件和功能
-
Python友好:使用Python语言开发,学习曲线平缓
-
美观易用:支持自定义样式,可打造现代化界面
项目架构
整个项目采用面向对象设计,主要包含以下模块:
scss
MacStyleRobocopyUI
├── initUI() - 界面初始化
├── setupMacStyle() - Mac风格样式设置
├── browse_source()/browse_dest()/browse_log() - 文件浏览
├── execute_copy() - 执行复制操作
├── handle_stdout()/handle_stderr() - 输出处理
├── process_finished() - 进程结束处理
├── show_help() - 显示帮助信息
├── show_donation() - 显示赞赏码
└── exit_app() - 退出应用
核心功能实现详解
1. 界面布局设计
界面采用分组布局,将功能划分为多个逻辑区域:
ini
# 路径设置组
path_group = QGroupBox("路径设置")
path_layout = QGridLayout()
path_layout.addWidget(QLabel("源目录:"),0,0)
self.source_dir = QLineEdit()
path_layout.addWidget(self.source_dir,0,1)
self.source_browse = QPushButton("浏览")
path_layout.addWidget(self.source_browse,0,2)
# ... 其他路径设置
主要功能区域包括:
-
路径设置:源目录、目标目录和文件筛选
-
基本复制选项:常用的Robocopy参数复选框
-
高级选项:重试设置、高级复制选项
-
筛选和日志设置:文件大小筛选、排除设置和日志配置
-
执行区域:控制按钮和输出日志
2. Mac风格样式实现
为了打造现代化界面,我使用了QSS(Qt Style Sheets)自定义样式:
less
defsetupMacStyle(self):
self.setStyleSheet("""
QMainWindow {
background-color: #f5f5f7;
font-family: '.SF NS Text', 'San Francisco', sans-serif;
}
QPushButton {
background-color: #007AFF;
border: none;
color: white;
padding: 8px 16px;
border-radius: 6px;
font-weight: 500;
}
QPushButton:hover {
background-color: #0062CC;
}
/* ... 其他样式设置 */
""")
3. Robocopy命令构建与执行
核心功能是将用户界面输入转换为Robocopy命令:
python
defexecute_copy(self):
# 检查必要参数
ifnot self.source_dir.text()ornot self.dest_dir.text():
QMessageBox.warning(self,"警告","请设置源目录和目标目录")
return
# 构建robocopy命令
command =["robocopy", self.source_dir.text(), self.dest_dir.text()]
# 添加选项
if self.s_option.isChecked():
command.append("/S")
if self.e_option.isChecked():
command.append("/E")
# ... 其他选项处理
# 在线程中执行命令
self.process = QProcess(self)
self.process.readyReadStandardOutput.connect(self.handle_stdout)
self.process.start("cmd",["/c"]+ command)
4. 实时输出与进度显示
为了提升用户体验,实现了实时输出和进度显示:
scss
defhandle_stdout(self):
data = self.process.readAllStandardOutput()
stdout =bytes(data).decode("gbk", errors="ignore")
self.output_area.append(stdout)
# 进度模拟
current_value = self.progress_bar.value()
if current_value <90:
self.progress_bar.setValue(current_value +1)
功能亮点与使用场景
主要功能亮点
-
多线程复制 :通过
/MT
选项支持1-128线程复制,大幅提升速度 -
镜像模式 :
/MIR
选项实现目录镜像,自动同步和删除文件 -
详细日志:支持日志记录和Unicode日志,便于追踪复制过程
-
文件筛选:按大小、名称等条件筛选文件,精确控制复制内容
-
断点续传 :
/Z
选项支持可重启模式,适合大文件传输
适用场景
-
系统备份:定期备份重要文件和目录
-
文件迁移:更换电脑或硬盘时迁移数据
-
服务器同步:多台服务器间文件同步
-
批量处理:按条件筛选并复制特定文件
-
网络传输:通过网络共享复制大文件
使用指南
-
下载与安装:
这款工具完全免费,源代码开放,获取方式如下:
《Robocopy文件复制工具》下载链接
百度网盘分享链接: 提取码: 6ke9
bashhttps://pan.baidu.com/s/1ssS2Uz2XQtjxQV9uN124Ng?pwd=6ke9
夸克网盘分享链接:提取码:5hYT
bashhttps://pan.quark.cn/s/8afd32e74fa2?pwd=5hYT
-
基本操作:
-
- 选择源目录和目标目录
- 选择复制选项(如/S复制子目录)
- 点击"开始复制"按钮
- 在输出区域查看复制进度和结果
-
高级技巧:
-
-
使用镜像模式
/MIR
保持目录完全同步 -
配置多线程
/MT
加速大文件复制 -
设置日志记录以便后续查看
-
总结与展望
通过Trae实现Robocopy可视化界面,不仅解决了命令行工具使用复杂的问题,还通过现代化UI设计提升了用户体验。这个工具特别适合程序员小白和需要频繁处理文件复制的用户。
如果你觉得这个工具对你有帮助,欢迎:
• 点赞和分享给需要的朋友
• 关注作者获取更多实用工具
• 扫描下方二维码给作者一点鼓励

源代码如下
python
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Robocopy 文件复制工具 1.05
版权所有 (C) 2025 于海峰
微信: 5727717
这是一个基于PyQt5的Robocopy图形界面工具,提供了文件复制、移动、镜像等功能。
"""
import sys
import subprocess
import threading
from PyQt5.QtWidgets import (QApplication, QMainWindow, QWidget, QVBoxLayout, QHBoxLayout,
QGroupBox, QLabel, QLineEdit, QPushButton, QCheckBox, QSpinBox,
QTextEdit, QComboBox, QGridLayout, QFileDialog, QProgressBar,
QMessageBox, QFrame, QDialog, QTextBrowser) # 确保包含了 QDialog
from PyQt5.QtCore import Qt, QTimer, QProcess
from PyQt5.QtGui import QFont, QIcon, QColor, QPalette, QPixmap # 确保包含了 QPixmap
class MacStyleRobocopyUI(QMainWindow):
def __init__(self):
super().__init__()
self.process = None
self.initUI()
self.setupMacStyle()
def initUI(self):
# 主窗口设置
self.setWindowTitle("Robocopy 文件复制工具 1.05")
self.setGeometry(100, 100, 1000, 800) # 将高度从750修改为800
# 中央部件
central_widget = QWidget()
self.setCentralWidget(central_widget)
# 主布局
main_layout = QVBoxLayout(central_widget)
main_layout.setSpacing(15)
main_layout.setContentsMargins(20, 20, 20, 20)
# 标题
title_label = QLabel("Robocopy 文件复制工具")
title_label.setAlignment(Qt.AlignCenter)
title_label.setObjectName("title")
title_label.setFixedHeight(40) # 设置标签固定高度为40像素
main_layout.addWidget(title_label)
# 添加一个小间距(5像素),缩小标题和路径设置组之间的间隔
main_layout.addSpacing(5)
# 路径设置组
path_group = QGroupBox("路径设置")
path_layout = QGridLayout()
path_layout.setSpacing(10)
path_layout.addWidget(QLabel("源目录:"), 0, 0)
self.source_dir = QLineEdit()
self.source_dir.setPlaceholderText("请选择源目录")
path_layout.addWidget(self.source_dir, 0, 1)
self.source_browse = QPushButton("浏览")
path_layout.addWidget(self.source_browse, 0, 2)
path_layout.addWidget(QLabel("目标目录:"), 1, 0)
self.dest_dir = QLineEdit()
self.dest_dir.setPlaceholderText("请选择目标目录")
path_layout.addWidget(self.dest_dir, 1, 1)
self.dest_browse = QPushButton("浏览")
path_layout.addWidget(self.dest_browse, 1, 2)
path_layout.addWidget(QLabel("文件筛选:"), 2, 0)
self.file_filter = QLineEdit("例如: *.txt 或 *.doc")
path_layout.addWidget(self.file_filter, 2, 1)
path_group.setLayout(path_layout)
main_layout.addWidget(path_group)
# 创建水平布局用于并排显示基本复制选项和高级选项组
options_layout = QHBoxLayout() # 修复:定义options_layout
options_layout.setSpacing(15)
# 基本复制选项组
basic_group = QGroupBox("基本复制选项")
basic_layout = QGridLayout()
basic_layout.setSpacing(10)
self.s_option = QCheckBox("/S - 复制子目录(排除空目录)")
basic_layout.addWidget(self.s_option, 0, 0)
self.sec_option = QCheckBox("/SEC - 复制安全信息")
basic_layout.addWidget(self.sec_option, 0, 1)
self.mov_option = QCheckBox("/MOV - 移动文件")
basic_layout.addWidget(self.mov_option, 0, 2)
self.e_option = QCheckBox("/E - 复制子目录(包括空目录)")
basic_layout.addWidget(self.e_option, 1, 0)
self.copyall_option = QCheckBox("/COPYALL - 复制所有文件信息")
basic_layout.addWidget(self.copyall_option, 1, 1)
self.move_option = QCheckBox("/MOVE - 移动文件和目录")
basic_layout.addWidget(self.move_option, 1, 2)
self.mir_option = QCheckBox("/MIR - 镜像模式")
basic_layout.addWidget(self.mir_option, 2, 0)
self.z_option = QCheckBox("/Z - 可重启模式")
basic_layout.addWidget(self.z_option, 2, 1)
self.create_option = QCheckBox("/CREATE - 仅创建目录结构")
basic_layout.addWidget(self.create_option, 2, 2)
self.purge_option = QCheckBox("/PURGE - 删除目标中不存在的文件")
basic_layout.addWidget(self.purge_option, 3, 0)
self.b_option = QCheckBox("/B - 备份模式")
basic_layout.addWidget(self.b_option, 3, 1)
basic_layout.addWidget(QLabel("/MT - 多线程:"), 3, 2)
self.mt_option = QSpinBox()
self.mt_option.setRange(1, 128)
self.mt_option.setValue(16)
basic_layout.addWidget(self.mt_option, 3, 3)
basic_group.setLayout(basic_layout)
# 高级选项组
advanced_group = QGroupBox("高级选项")
advanced_layout = QGridLayout()
advanced_layout.setSpacing(10)
self.fat_option = QCheckBox("/FAT - 使用8.3 FAT文件名")
advanced_layout.addWidget(self.fat_option, 0, 0)
self.v_option = QCheckBox("/V - 详细输出")
advanced_layout.addWidget(self.v_option, 0, 1)
# 添加垂直分隔线
line = QFrame()
line.setFrameShape(QFrame.VLine)
line.setFrameShadow(QFrame.Sunken)
advanced_layout.addWidget(line, 0, 2, 3, 1) # 跨越0-2行,列2
advanced_layout.addWidget(QLabel("重试设置"), 0, 3)
self.j_option = QCheckBox("/J - 使用无缓冲I/O")
advanced_layout.addWidget(self.j_option, 1, 0)
self.l_option = QCheckBox("/L - 仅列出不复制")
advanced_layout.addWidget(self.l_option, 1, 1)
advanced_layout.addWidget(QLabel("重试次数:"), 1, 3)
self.retry_count = QSpinBox()
self.retry_count.setRange(0, 100)
self.retry_count.setValue(1)
advanced_layout.addWidget(self.retry_count, 1, 4)
self.nocopy_option = QCheckBox("/NOCOPY - 不复制文件信息")
advanced_layout.addWidget(self.nocopy_option, 2, 0)
self.nfl_option = QCheckBox("/NFL - 不列文件")
advanced_layout.addWidget(self.nfl_option, 2, 1)
advanced_layout.addWidget(QLabel("等待时间:"), 2, 3)
self.wait_time = QLineEdit("30")
advanced_layout.addWidget(self.wait_time, 2, 4)
advanced_group.setLayout(advanced_layout)
# 将两个选项组添加到水平布局中
options_layout.addWidget(basic_group)
options_layout.addWidget(advanced_group)
# 将水平布局添加到主布局
main_layout.addLayout(options_layout)
# 创建另一个水平布局用于并排显示筛选和日志选项组
bottom_layout = QHBoxLayout()
bottom_layout.setSpacing(15)
# 软件筛选选项组
filter_group = QGroupBox("软件筛选选项")
filter_layout = QGridLayout()
filter_layout.setSpacing(10)
filter_layout.addWidget(QLabel("文件大小: 最小"), 0, 0)
self.min_size = QLineEdit()
filter_layout.addWidget(self.min_size, 0, 1)
filter_layout.addWidget(QLabel("最大"), 0, 2)
self.max_size = QLineEdit()
filter_layout.addWidget(self.max_size, 0, 3)
filter_layout.addWidget(QLabel("(单位: KB)"), 0, 4)
filter_layout.addWidget(QLabel("排除文件:"), 1, 0)
self.exclude_files = QLineEdit()
self.exclude_files.setPlaceholderText("例如: *.tmp *.bak")
filter_layout.addWidget(self.exclude_files, 1, 1, 1, 4)
filter_layout.addWidget(QLabel("排除目录:"), 2, 0)
self.exclude_dirs = QLineEdit()
filter_layout.addWidget(self.exclude_dirs, 2, 1, 1, 4)
filter_group.setLayout(filter_layout)
# 日志设置组
log_group = QGroupBox("日志设置")
log_layout = QGridLayout()
log_layout.setSpacing(10)
self.enable_log = QCheckBox("启用日志记录")
log_layout.addWidget(self.enable_log, 0, 0)
self.unicode_log = QCheckBox("Unicode日志")
log_layout.addWidget(self.unicode_log, 0, 1)
self.append_log = QCheckBox("追加日志")
log_layout.addWidget(self.append_log, 0, 2)
log_layout.addWidget(QLabel("日志文件:"), 1, 0)
self.log_file = QLineEdit()
log_layout.addWidget(self.log_file, 1, 1)
self.log_browse = QPushButton("浏览")
log_layout.addWidget(self.log_browse, 1, 2)
log_group.setLayout(log_layout)
# 创建绿色分隔线
separator = QFrame()
separator.setFrameShape(QFrame.VLine)
separator.setFrameShadow(QFrame.Sunken)
separator.setStyleSheet("color: green; background-color: green;")
# 将筛选和日志组添加到水平布局中,中间加入分隔线
bottom_layout.addWidget(filter_group)
bottom_layout.addWidget(separator)
bottom_layout.addWidget(log_group)
# 将水平布局添加到主布局
main_layout.addLayout(bottom_layout)
# 进度条
self.progress_bar = QProgressBar()
self.progress_bar.setValue(0)
self.progress_bar.setObjectName("progress")
main_layout.addWidget(self.progress_bar)
# 执行按钮布局
button_layout = QHBoxLayout()
button_layout.setSpacing(10)
self.execute_button = QPushButton("开始复制")
self.execute_button.setObjectName("execute")
self.help_button = QPushButton("使用说明")
self.help_button.setObjectName("help")
self.donate_button = QPushButton("赞赏支持") # 新增:添加赞赏按钮
self.donate_button.setObjectName("donate") # 新增:设置赞赏按钮对象名称
self.exit_button = QPushButton("退出")
self.exit_button.setObjectName("exit")
self.exit_button.setEnabled(True)
button_layout.addWidget(self.execute_button)
button_layout.addWidget(self.help_button)
button_layout.addWidget(self.donate_button) # 新增:添加赞赏按钮到布局
button_layout.addWidget(self.exit_button)
main_layout.addLayout(button_layout)
# 输出区域
output_label = QLabel("输出日志:")
main_layout.addWidget(output_label)
self.output_area = QTextEdit()
self.output_area.setReadOnly(True)
self.output_area.setMaximumHeight(150)
main_layout.addWidget(self.output_area)
# 连接信号和槽
self.source_browse.clicked.connect(self.browse_source)
self.dest_browse.clicked.connect(self.browse_dest)
self.log_browse.clicked.connect(self.browse_log)
self.execute_button.clicked.connect(self.execute_copy)
self.help_button.clicked.connect(self.show_help)
self.donate_button.clicked.connect(self.show_donation) # 新增:连接赞赏按钮信号
self.exit_button.clicked.connect(self.exit_app)
def setupMacStyle(self):
# 设置苹果风格样式表
self.setStyleSheet("""
QMainWindow {
background-color: #f5f5f7;
font-family: '.SF NS Text', 'San Francisco', 'Helvetica Neue', sans-serif;
}
#title {
font-size: 24px;
font-weight: 500;
color: #333333;
margin: 10px;
}
QGroupBox {
font-weight: 500;
border: 1px solid #d1d1d6;
border-radius: 8px;
margin-top: 25px;
padding-top: 15px;
background-color: white;
font-size: 14px;
}
QGroupBox::title {
subcontrol-offset: -20px; /* 修改:将subline-offset改为subcontrol-offset */
padding: 0 10px;
color: #333333;
}
QPushButton {
background-color: #007AFF;
border: none;
color: white;
padding: 8px 16px;
text-align: center;
font-size: 14px;
border-radius: 6px;
font-weight: 500;
min-height: 30px;
}
QPushButton:hover {
background-color: #0062CC;
}
QPushButton:pressed {
background-color: #004999;
}
QPushButton#help { /* 新增:帮助按钮样式 */
background-color: #4CAF50;
color: white;
border: none;
padding: 8px 16px;
border-radius: 4px;
font-size: 13px;
font-weight: 500;
subline-offset: -1px; /* 修正拼写错误:subcontrol-offset -> subline-offset */
}
QPushButton#help:hover { /* 新增:帮助按钮悬停样式 */
background-color: #2DA448;
}
QPushButton#help:pressed { /* 新增:帮助按钮按下样式 */
background-color: #218838;
}
QPushButton#donate { /* 新增:赞赏按钮样式 */
background-color: #FF9500;
color: white;
border: none;
padding: 8px 16px;
border-radius: 4px;
font-size: 13px;
font-weight: 500;
}
QPushButton#donate:hover { /* 新增:赞赏按钮悬停样式 */
background-color: #E88B00;
}
QPushButton#donate:pressed { /* 新增:赞赏按钮按下样式 */
background-color: #CC7700;
}
QPushButton#exit { /* 修改:更新CSS选择器 */
background-color: #FF3B30;
}
QPushButton#exit:hover { /* 修改:更新CSS选择器 */
background-color: #D4261F;
}
QPushButton#exit:pressed { /* 修改:更新CSS选择器 */
background-color: #B2120F;
}
QPushButton:disabled {
background-color: #C7C7CC;
color: #FFFFFF;
}
QLineEdit {
padding: 8px;
border: 1px solid #d1d1d6;
border-radius: 6px;
font-size: 14px;
background-color: white;
}
QLineEdit:focus {
border: 1px solid #007AFF;
outline: none;
}
QTextEdit {
border: 1px solid #d1d1d6;
border-radius: 6px;
background-color: white;
font-family: 'Monaco', 'Consolas', monospace;
font-size: 12px;
}
QCheckBox {
spacing: 5px;
font-size: 14px;
}
QCheckBox::indicator {
width: 18px;
height: 18px;
border-radius: 4px;
border: 1px solid #d1d1d6;
background-color: white;
}
QCheckBox::indicator:checked {
background-color: #007AFF;
border: 1px solid #007AFF;
image: url();
}
QSpinBox {
padding: 6px;
border: 1px solid #d1d1d6;
border-radius: 6px;
font-size: 14px;
background-color: white;
}
QSpinBox::up-button, QSpinBox::down-button {
width: 20px;
border: none;
background-color: transparent;
}
QLabel {
font-size: 14px;
color: #333333;
}
#progress {
border: 1px solid #d1d1d6;
border-radius: 6px;
background-color: #f0f0f0;
text-align: center;
}
#progress::chunk {
background-color: #007AFF;
border-radius: 5px;
}
""")
def browse_source(self):
directory = QFileDialog.getExistingDirectory(self, "选择源目录")
if directory:
self.source_dir.setText(directory)
def browse_dest(self):
directory = QFileDialog.getExistingDirectory(self, "选择目标目录")
if directory:
self.dest_dir.setText(directory)
def browse_log(self):
file_path, _ = QFileDialog.getSaveFileName(self, "选择日志文件", "", "日志文件 (*.log);;所有文件 (*)")
if file_path:
self.log_file.setText(file_path)
def execute_copy(self):
# 检查必要参数
if not self.source_dir.text() or not self.dest_dir.text():
QMessageBox.warning(self, "警告", "请设置源目录和目标目录")
return
# 构建robocopy命令
command = ["robocopy", self.source_dir.text(), self.dest_dir.text()]
# 添加文件筛选
if self.file_filter.text():
command.append(self.file_filter.text())
# 添加选项
if self.s_option.isChecked():
command.append("/S")
if self.e_option.isChecked():
command.append("/E")
if self.sec_option.isChecked():
command.append("/SEC")
if self.mov_option.isChecked():
command.append("/MOV")
if self.copyall_option.isChecked():
command.append("/COPYALL")
if self.move_option.isChecked():
command.append("/MOVE")
if self.mir_option.isChecked():
command.append("/MIR")
if self.z_option.isChecked():
command.append("/Z")
if self.create_option.isChecked():
command.append("/CREATE")
if self.purge_option.isChecked():
command.append("/PURGE")
if self.b_option.isChecked():
command.append("/B")
if self.mt_option.value() > 1:
command.append(f"/MT:{self.mt_option.value()}")
if self.fat_option.isChecked():
command.append("/FAT")
if self.v_option.isChecked():
command.append("/V")
if self.j_option.isChecked():
command.append("/J")
if self.l_option.isChecked():
command.append("/L")
if self.retry_count.value() > 0:
command.append(f"/R:{self.retry_count.value()}")
if self.nocopy_option.isChecked():
command.append("/NOCOPY")
if self.nfl_option.isChecked():
command.append("/NFL")
if self.wait_time.text():
command.append(f"/W:{self.wait_time.text()}")
if self.min_size.text():
command.append(f"/MIN:{self.min_size.text()}")
if self.max_size.text():
command.append(f"/MAX:{self.max_size.text()}")
if self.exclude_files.text():
command.append(f"/XF {self.exclude_files.text()}")
if self.exclude_dirs.text():
command.append(f"/XD {self.exclude_dirs.text()}")
if self.enable_log.isChecked():
command.append(f"/LOG:{self.log_file.text()}")
if self.unicode_log.isChecked():
command.append("/UNILOG")
if self.append_log.isChecked():
command.append("/APP")
# 更新UI状态
self.execute_button.setEnabled(False)
# self.stop_button.setEnabled(True) # 删除:不再需要
self.output_area.clear()
self.progress_bar.setValue(0)
# 在线程中执行命令
self.process = QProcess(self)
self.process.readyReadStandardOutput.connect(self.handle_stdout)
self.process.readyReadStandardError.connect(self.handle_stderr)
self.process.finished.connect(self.process_finished)
self.process.start("cmd", ["/c"] + command)
def handle_stdout(self):
data = self.process.readAllStandardOutput()
stdout = bytes(data).decode("gbk", errors="ignore")
self.output_area.append(stdout)
# 简单的进度模拟(实际应用中可以根据输出内容更新进度)
current_value = self.progress_bar.value()
if current_value < 90: # 留一些空间给最后的完成步骤
self.progress_bar.setValue(current_value + 1)
def handle_stderr(self):
data = self.process.readAllStandardError()
stderr = bytes(data).decode("gbk", errors="ignore")
self.output_area.append(stderr)
def process_finished(self):
self.execute_button.setEnabled(True)
# self.stop_button.setEnabled(False) # 删除:不再需要
self.progress_bar.setValue(100)
self.output_area.append("\n复制操作已完成")
def exit_app(self): # 修改:添加退出应用程序的函数
"""退出应用程序"""
# 如果有正在运行的进程,先终止它
if self.process and self.process.state() == QProcess.Running:
self.process.kill()
# 关闭应用程序
QApplication.instance().quit()
def show_help(self): # 新增:显示帮助信息的函数
"""显示使用说明"""
help_text = """
-------------------------------------------------------------------------------
ROBOCOPY :: Windows 的可靠文件复制
-------------------------------------------------------------------------------
Copyright @2025 By 于海峰 Wx:5727717
用法 :: ROBOCOPY source destination [file [file]...] [options]
源 :: 源目录(驱动器:\路径或\\服务器\共享\路径)。
目标 :: 目标目录(驱动器:\路径或\\服务器\共享\路径)。
文件 :: 要复制的文件(名称/通配符: 默认为 "*.*")。
::
:: 复制选项:
::
/S :: 复制子目录,但不复制空的子目录。
/E :: 复制子目录,包括空的子目录。
/LEV:n :: 仅复制源目录树的前 n 层。
/Z :: 在可重新启动模式下复制文件。
/B :: 在备份模式下复制文件。
/ZB :: 使用可重新启动模式;如果拒绝访问,请使用备份模式。
/J :: 复制时使用无缓冲的 I/O (推荐在复制大文件时使用)。
/EFSRAW :: 在 EFS RAW 模式下复制所有加密的文件。
/COPY:复制标记:: 要复制的文件内容(默认为 /COPY:DAT)。
(复制标记: D=数据,A=属性,T=时间戳)。
(S=安全=NTFS ACL,O=所有者信息,U=审核信息)。
/SEC :: 复制具有安全性的文件(等同于 /COPY:DATS)。
/COPYALL :: 复制所有文件信息(等同于 /COPY:DATSOU)。
/NOCOPY :: 不复制任何文件信息(与 /PURGE 一起使用)。
/SECFIX :: 修复所有文件的文件安全性,即使是跳过的文件。
/TIMFIX :: 修复所有文件的文件时间,即使是跳过的文件。
/PURGE :: 删除源中不再存在的目标文件/目录。
/MIR :: 镜像目录树(等同于 /E 加 /PURGE)。
/MOV :: 移动文件(复制后从源中删除)。
/MOVE :: 移动文件和目录(复制后从源中删除)。
/A+:[RASHCNET] :: 将给定的属性添加到复制的文件。
/A-:[RASHCNET] :: 从复制的文件中删除给定的属性。
/CREATE :: 仅创建目录树和长度为零的文件。
/FAT :: 仅使用 8.3 FAT 文件名创建目标文件。
/256 :: 关闭超长路径(> 256 个字符)支持。
/MON:n :: 监视源;发现多于 n 个更改时再次运行。
/MOT:m :: 监视源;如果更改,在 m 分钟时间后再次运行。
/RH:hhmm-hhmm :: 可以启动新的复制时运行的小时数 - 时间。
/PF :: 基于每个文件(而不是每个步骤)来检查运行小时数。
/IPG:n :: 程序包间的间距(ms),以释放低速线路上的带宽。
/SL :: 对照目标复制符号链接。
/MT[:n] :: 使用 n 个线程进行多线程复制(默认值为 8)。
n 必须至少为 1,但不得大于 128。
该选项与 /IPG 和 /EFSRAW 选项不兼容。
使用 /LOG 选项重定向输出以便获得最佳性能。
/DCOPY:复制标记:: 要复制的目录内容(默认为 /DCOPY:DA)。
(复制标记: D=数据,A=属性,T=时间戳)。
/NODCOPY :: 不复制任何目录信息(默认情况下,执行 /DCOPY:DA)。
/NOOFFLOAD :: 在不使用 Windows 复制卸载机制的情况下复制文件。
::
:: 文件选择选项:
::
/A :: 仅复制具有存档属性集的文件。
/M :: 仅复制具有存档属性的文件并重置存档属性。
/IA:[RASHCNETO] :: 仅包含具有任意给定属性集的文件。
/XA:[RASHCNETO] :: 排除具有任意给定属性集的文件。
/XF 文件[文件]... :: 排除与给定名称/路径/通配符匹配的文件。
/XD 目录[目录]... :: 排除与给定名称/路径匹配的目录。
/XC :: 排除已更改的文件。
/XN :: 排除较新的文件。
/XO :: 排除较旧的文件。
/XX :: 排除多余的文件和目录。
/XL :: 排除孤立的文件和目录。
/IS :: 包含相同文件。
/IT :: 包含已调整的文件。
/MAX:n :: 最大的文件大小 - 排除大于 n 字节的文件。
/MIN:n :: 最小的文件大小 - 排除小于 n 字节的文件。
/MAXAGE:n :: 最长的文件存在时间 - 排除早于 n 天/日期的文件。
/MINAGE:n :: 最短的文件存在时间 - 排除晚于 n 天/日期的文件。
/MAXLAD:n :: 最大的最后访问日期 - 排除自 n 以来未使用的文件。
/MINLAD:n :: 最小的最后访问日期 - 排除自 n 以来使用的文件。
(If n < 1900 then n = n days, else n = YYYYMMDD date)。
/XJ :: 排除接合点和符号链接。(默认情况下通常包括)。
/FFT :: 假设 FAT 文件时间(2 秒粒度)。
/DST :: 弥补 1 小时的 DST 时间差。
/XJD :: 排除目录的接合点和符号链接。
/XJF :: 排除文件的符号链接。
::
:: 重试选项:
::
/R:n :: 失败副本的重试次数: 默认为 1 百万。
/W:n :: 两次重试间的等待时间: 默认为 30 秒。
/REG :: 将注册表中的 /R:n 和 /W:n 保存为默认设置。
/TBD :: 等待定义共享名称(重试错误 67)。
::
:: 日志记录选项:
::
/L :: 仅列出 - 不复制、添加时间戳或删除任何文件。
/X :: 报告所有多余的文件,而不只是选中的文件。
/V :: 生成详细输出,同时显示跳过的文件。
/TS :: 在输出中包含源文件的时间戳。
/FP :: 在输出中包含文件的完整路径名称。
/BYTES :: 以字节打印大小。
/NS :: 无大小 - 不记录文件大小。
/NC :: 无类别 - 不记录文件类别。
/NFL :: 无文件列表 - 不记录文件名。
/NDL :: 无目录列表 - 不记录目录名称。
/NP :: 无进度 - 不显示已复制的百分比。
/ETA :: 显示复制文件的预期到达时间。
/LOG:文件 :: 将状态输出到日志文件(覆盖现有日志)。
/LOG+:文件 :: 将状态输出到日志文件(附加到现有日志中)。
/UNILOG:文件 :: 以 UNICODE 方式将状态输出到日志文件(覆盖现有日志)。
/UNILOG+:文件 :: 以 UNICODE 方式将状态输出到日志文件(附加到现有日志中)。
/TEE :: 输出到控制台窗口和日志文件。
/NJH :: 没有作业标头。
/NJS :: 没有作业摘要。
/UNICODE :: 以 UNICODE 方式输出状态。
::
:: 作业选项 :
::
/JOB:作业名称 :: 从命名的作业文件中提取参数。
/SAVE:作业名称 :: 将参数保存到命名的作业文件
/QUIT :: 处理命令行后退出(以查看参数)。
/NOSD :: 未指定源目录。
/NODD :: 未指定目标目录。
/IF :: 包含以下文件。
::
:: 备注:
::
以前在卷的根目录上使用 /PURGE 或 /MIR 导致
robocopy 也对"系统卷信息"目录内的
文件应用所请求的操作。现在不再是这种情形;如果
指定了任何一项,则 robocopy 将跳过
复制会话简要源目录和目标目录中具有该名称的任何文件或目录。
"""
# 创建帮助对话框
help_dialog = QDialog(self)
help_dialog.setWindowTitle("Robocopy 使用说明")
help_dialog.resize(800, 600) # 设置对话框大小
# 创建垂直布局
layout = QVBoxLayout(help_dialog)
# 创建 QTextBrowser 并设置帮助文本
text_browser = QTextBrowser()
text_browser.setPlainText(help_text)
# 创建关闭按钮
close_button = QPushButton("关闭")
close_button.clicked.connect(help_dialog.accept)
# 将 QTextBrowser 和按钮添加到布局中
layout.addWidget(text_browser)
layout.addWidget(close_button)
# 显示对话框
help_dialog.exec_()
def show_donation(self): # 新增:显示赞赏码的函数
"""显示赞赏码"""
# 创建赞赏对话框
donate_dialog = QDialog(self)
donate_dialog.setWindowTitle("赞赏支持")
donate_dialog.resize(400, 500) # 设置对话框大小
# 创建垂直布局
layout = QVBoxLayout(donate_dialog)
# 创建标签显示赞赏信息
info_label = QLabel("如果该作品对你有帮助,可打赏,谢谢你的支持")
info_label.setAlignment(Qt.AlignCenter)
info_label.setStyleSheet("font-size: 16px; font-weight: bold; margin: 10px;")
layout.addWidget(info_label)
# 创建标签显示二维码
qr_label = QLabel()
qr_label.setAlignment(Qt.AlignCenter)
# 加载二维码图片
try:
pixmap = QPixmap("e:/Codes/Robocopy界面/于海峰的赞赏码.png")
if pixmap.isNull():
qr_label.setText("无法加载赞赏码图片")
else:
# 调整图片大小以适应对话框
scaled_pixmap = pixmap.scaled(300, 300, Qt.KeepAspectRatio, Qt.SmoothTransformation)
qr_label.setPixmap(scaled_pixmap)
except Exception as e:
qr_label.setText(f"加载图片时出错: {str(e)}")
layout.addWidget(qr_label)
# 创建标签显示作者信息
author_label = QLabel("于海峰 的赞赏码")
author_label.setAlignment(Qt.AlignCenter)
author_label.setStyleSheet("font-size: 14px; margin: 10px;")
layout.addWidget(author_label)
# 创建关闭按钮
close_button = QPushButton("关闭")
close_button.clicked.connect(donate_dialog.accept)
layout.addWidget(close_button)
# 显示对话框
donate_dialog.exec_()
def main():
app = QApplication(sys.argv)
# 设置应用程序全局字体
font = QFont(".SF NS Text", 10)
app.setFont(font)
window = MacStyleRobocopyUI()
window.show()
sys.exit(app.exec_())
if __name__ == "__main__":
main()