文章目录
- 使用 QGroupBox + QHBoxLayout: 标签:路径 输入框:self.dir_edit 浏览按钮:浏览…,通过 QFileDialog.getExistingDirectory 让用户选择目录 dir_group = QGroupBox(“目标目录”) dir_layout = QHBoxLayout() dir_label = QLabel(“路径”) self.dir_edit = QLineEdit() browse_btn = QPushButton(“浏览…”) browse_btn.clicked.connect(self.browse_dir) dir_layout.addWidget(dir_label) dir_layout.addWidget(self.dir_edit, 1) dir_layout.addWidget(browse_btn) dir_group.setLayout(dir_layout) main_layout.addWidget(dir_group) browse_dir 很简单,从对话框拿到目录再写入输入框: def browse_dir(self): directory = QFileDialog.getExistingDirectory(self, “选择目标目录”) if directory: self.dir_edit.setText(directory)
- 规则区域用了一个大的 QGroupBox("规则设置"),里面再嵌两个部分: 上半:规则编辑器(操作类型 + 参数1 + 参数2 + 添加规则按钮) 下半:当前规则列表(表格)+ 规则操作按钮 规则编辑器部分: builder_form = QFormLayout() op_label = QLabel(“操作类型”) self.op_combo = QComboBox() self.op_combo.addItem(“前面添加”, “prefix”) self.op_combo.addItem(“后面添加”, “suffix”) self.op_combo.addItem(“替换”, “replace”) self.op_combo.addItem(“删除字符”, “delete”) self.param1_label = QLabel(“参数1”) self.param1_edit = QLineEdit() self.param2_label = QLabel(“参数2”) self.param2_edit = QLineEdit() builder_form.addRow(op_label, self.op_combo) builder_form.addRow(self.param1_label, self.param1_edit) builder_form.addRow(self.param2_label, self.param2_edit) add_row = QHBoxLayout() add_row.addStretch() self.add_op_btn = QPushButton(“添加规则”) add_row.addWidget(self.add_op_btn) builder_form.addRow(QLabel(“”), add_row) 规则列表表格: self.ops_table = QTableWidget() self.ops_table.setColumnCount(4) self.ops_table.setHorizontalHeaderLabels([“顺序”, “类型”, “参数1”, “参数2”]) self.ops_table.setAlternatingRowColors(True) self.ops_table.setSelectionBehavior(QAbstractItemView.SelectRows) self.ops_table.setSelectionMode(QAbstractItemView.SingleSelection) self.ops_table.setEditTriggers(QAbstractItemView.NoEditTriggers) self.ops_table.horizontalHeader().setSectionResizeMode(0, QHeaderView.ResizeToContents) self.ops_table.horizontalHeader().setSectionResizeMode(1, QHeaderView.ResizeToContents) self.ops_table.horizontalHeader().setSectionResizeMode(2, QHeaderView.Stretch) self.ops_table.horizontalHeader().setSectionResizeMode(3, QHeaderView.Stretch) self.ops_table.verticalHeader().setVisible(False) self.ops_table.setShowGrid(False) 表格下面是几个操作按钮: 上移 下移 删除 清空
- 两个主按钮: btn_layout = QHBoxLayout() self.preview_btn = QPushButton(“预览”) self.apply_btn = QPushButton(“执行重命名”) btn_layout.addStretch() btn_layout.addWidget(self.preview_btn) btn_layout.addWidget(self.apply_btn) main_layout.addLayout(btn_layout) 下方结果表格: self.table = QTableWidget() self.table.setColumnCount(3) self.table.setHorizontalHeaderLabels([“原目录名”, “新目录名”, “状态”]) self.table.setAlternatingRowColors(True) self.table.setSelectionBehavior(QAbstractItemView.SelectRows) self.table.setSelectionMode(QAbstractItemView.SingleSelection) self.table.setEditTriggers(QAbstractItemView.NoEditTriggers) self.table.horizontalHeader().setSectionResizeMode(0, QHeaderView.Stretch) self.table.horizontalHeader().setSectionResizeMode(1, QHeaderView.Stretch) self.table.horizontalHeader().setSectionResizeMode(2, QHeaderView.ResizeToContents) self.table.verticalHeader().setVisible(False) self.table.setShowGrid(False)
- 在窗口类里维护一个列表: self.operations = [] 每条规则是一个字典: {“mode”: “prefix”, “p1”: “2026_”, “p2”: “”} {“mode”: “replace”, “p1″: ” “, “p2”: “_”} {“mode”: “delete”, “p1”: “test”, “p2”: “”} 添加规则时,把当前下拉框和参数输入框的值读出来,做一些校验后塞进 self.operations: def add_operation(self): mode = self.op_combo.currentData() p1 = self.param1_edit.text() p2 = self.param2_edit.text() if mode == “replace” and p1 == “”: QMessageBox.warning(self, “提示”, ““要替换”不能为空”) return if mode in (“prefix”, “suffix”, “delete”) and p1 == “”: QMessageBox.warning(self, “提示”, “参数不能为空”) return self.operations.append({“mode”: mode, “p1”: p1, “p2”: p2}) self.refresh_ops_table(select_index=len(self.operations) – 1) self.param1_edit.setText(“”) self.param2_edit.setText(“”) refresh_ops_table 把 self.operations 同步到规则表格里: def refresh_ops_table(self, select_index=None): self.ops_table.setRowCount(0) for i, op in enumerate(self.operations): row = self.ops_table.rowCount() self.ops_table.insertRow(row) self.ops_table.setItem(row, 0, QTableWidgetItem(str(i + 1))) self.ops_table.setItem(row, 1, QTableWidgetItem(self.mode_to_text(op[“mode”]))) self.ops_table.setItem(row, 2, QTableWidgetItem(op.get(“p1”, “”))) self.ops_table.setItem(row, 3, QTableWidgetItem(op.get(“p2”, “”))) 上移 / 下移 / 删除 / 清空其实就是对 self.operations 做 list 操作,然后调用 refresh_ops_table。
- 给某个目录名应用规则流水线: def apply_operations(self, name): new_name = name for op in self.operations: new_name = self.get_new_name(op[“mode”], new_name, op.get(“p1”, “”), op.get(“p2”, “”)) return new_name get_new_name 处理具体的四种模式: def get_new_name(self, mode, name, p1, p2): if mode == “prefix”: if not p1: return name return p1 + name if mode == “suffix”: if not p1: return name return name + p1 if mode == “replace”: if not p1: return name return name.replace(p1, p2) if mode == “delete”: if not p1: return name return name.replace(p1, “”) return name 预览时,就对目录下的每个子目录名调用一次 apply_operations,得到最终的新名字。
- 预览阶段,对每个目录算完新名字后,会先统计一遍数量: new_name_counts = {} computed = [] for name in dir_names: new_name = self.apply_operations(name) computed.append((name, new_name)) new_name_counts[new_name] = new_name_counts.get(new_name, 0) + 1 然后再逐条填到表格里,同时判断: if new_name == name: continue if not self.is_valid_dirname(new_name): status_item.setText(“冲突:非法名称”) continue if new_name_counts.get(new_name, 0) > 1: status_item.setText(“冲突:目标重复”) continue self.rename_tasks.append({“old_path”: old_path, “new_path”: new_path, “row”: row}) is_valid_dirname 简单过滤非法字符: def is_valid_dirname(self, name): if name is None: return False if name == “”: return False invalid_chars = set(‘<>:”/\|?*’) return not any(ch in invalid_chars for ch in name)
- 执行重命名时采用了一个「两阶段」策略: 第一阶段:把所有要改名的目录先重命名到一个临时名字(加上随机后缀) 第二阶段:再从这些临时名字统一改成目标新名字 这样就不会出现「A 改成 B,导致原来的 B 被挡住」的问题。 第一阶段: temp_map = {} stage1_ok = [] for t in valid_tasks: old_path = t[“old_path”] row = t[“row”] item = self.table.item(row, 2) tmp_path = f”{old_path}.__renametmp__{uuid.uuid4().hex}” try: os.rename(old_path, tmp_path) temp_map[tmp_path] = t stage1_ok.append(tmp_path) except Exception as e: msg = f”失败:{e}” item.setText(msg) 第二阶段: for tmp_path in stage1_ok: t = temp_map[tmp_path] new_path = t[“new_path”] row = t[“row”] item = self.table.item(row, 2) try: os.rename(tmp_path, new_path) item.setText(“成功”) except Exception as e: item.setText(f”失败:{e}”) try: os.rename(tmp_path, t[“old_path”]) except Exception: pass 这种方式的好处: 可以安全处理「互换名字」等复杂情况 即便第二阶段失败,也可以尝试把临时目录改回去,尽量保持原状
- PyInstaller 的 –icon 参数需要 .ico 文件,所以先用 Pillow 转一下: cd /d “D:测试Github项目61-目录批量改名” python -m pip install pillow python -c “from PIL import Image; Image.open(‘重命名.png’).save(‘重命名.ico’)” 这样目录下就会多出一个 重命名.ico。
- 在同一个目录下执行: pyinstaller -F -w –clean ^ –name “renamedir” ^ –icon “重命名.ico” ^ “renamedir.py” 参数含义: -F:单文件 EXE -w:不弹出控制台窗口 –clean:打包时清理缓存 –name "renamedir":生成的 exe 名叫 renamedir.exe –icon "重命名.ico":给 exe 加上自定义图标 打包完成后,会生成: D:测试Github项目61-目录批量改名 ├─ build ├─ dist │ └─ renamedir.exe └─ renamedir.spec 双击 distrenamedir.exe 就可以像普通 Windows 程序一样使用了。
目录
- 一、功能设计:从「单操作」到「规则流水线」
- 二、界面布局:一个小而美的 PyQt5 窗口
- 1. 目标目录区域
- 2. 规则配置区域:编辑 + 列表
- 3. 预览 / 执行区域
- 三、规则流水线:如何叠加多个操作
- 1. 规则的数据结构
- 2. 规则的执行:apply_operations
- 四、安全性:冲突检测与两阶段重命名
- 1. 合法性和重复的预览检查
- 2. 两阶段重命名:避免互相覆盖
- 五、让界面更好看一点:简单的 PyQt5 美化
- 六、运行结果
- 七、使用 PyInstaller 打包成单文件 EXE
- 1. 把 PNG 转成 ICO(用于 EXE 图标)
- 2. 打包命令
- 八、总结与可扩展方向
目录整理是一个非常常见但又枯燥的工作:比如下载了一堆带前缀/后缀的文件夹、备份目录前面都想加上日期、把目录名中的空格统一改成下划线……手工一个个改,很容易改到崩溃。
这篇文章记录我用 PyQt5 做了一个图形界面的小工具:支持对某个目录下所有子目录名进行 批量重命名,并且可以:
- 前面添加(前缀)
- 后面添加(后缀)
- 替换某个子串
- 删除某个子串
更重要的是:这些操作可以 叠加使用,按顺序从上到下执行。
最后再用 PyInstaller 打包成带自定义图标的单文件 renamedir.exe,方便在任何 Windows 上直接双击使用。
一开始的需求很简单:
选定一个目录,然后对它下面的一级子目录做统一的「前面添加 / 后面添加 / 替换 / 删除」。
这个版本的界面大概是这样:
- 一个「目标目录」选择框
- 一个「操作类型」下拉框(前面添加 / 后面添加 / 替换 / 删除)
- 两个参数输入框(比如「要替换」「替换为」)
- 一个「预览」按钮
- 一个下方表格,显示「原目录名」「新目录名」「状态」
- 一个「执行重命名」按钮
后来实际使用中,很快发现一个限制:
实际需求往往不是「只做一个操作」,而是类似:
- 先把目录名里的
test都删掉 - 再把空格替换成
_ - 最后前面加上日期前缀,比如
2026_
如果每次只能做一个操作,就要手动来回切换参数、预览、执行,非常不方便。
于是把「单次操作」升级成了 可叠加的规则列表:像流水线一样依次应用。
设计改动:
- 之前的「操作类型 + 参数」区域变成「规则编辑器」
- 下面新增一个「规则列表表格」
- 支持:
- 点击「添加规则」把当前操作加入列表
- 规则上移 / 下移调整顺序
- 删除单条规则
- 一键清空全部规则
- 预览时,会对每个目录名按规则列表的顺序依次执行
这样就可以放心地配置「先删、再替换、再加前缀/后缀」等组合操作了。
整个界面由三个部分组成:
- 顶部:目标目录区域
- 中间:规则配置区域
- 底部:预览和执行
使用 QGroupBox + QHBoxLayout:
- 标签:
路径 - 输入框:
self.dir_edit - 浏览按钮:
浏览...,通过QFileDialog.getExistingDirectory让用户选择目录
dir_group = QGroupBox("目标目录")
dir_layout = QHBoxLayout()
dir_label = QLabel("路径")
self.dir_edit = QLineEdit()
browse_btn = QPushButton("浏览...")
browse_btn.clicked.connect(self.browse_dir)
dir_layout.addWidget(dir_label)
dir_layout.addWidget(self.dir_edit, 1)
dir_layout.addWidget(browse_btn)
dir_group.setLayout(dir_layout)
main_layout.addWidget(dir_group)
browse_dir 很简单,从对话框拿到目录再写入输入框:
def browse_dir(self):
directory = QFileDialog.getExistingDirectory(self, "选择目标目录")
if directory:
self.dir_edit.setText(directory)
规则区域用了一个大的 QGroupBox("规则设置"),里面再嵌两个部分:
- 上半:规则编辑器(操作类型 + 参数1 + 参数2 + 添加规则按钮)
- 下半:当前规则列表(表格)+ 规则操作按钮
规则编辑器部分:
builder_form = QFormLayout()
op_label = QLabel("操作类型")
self.op_combo = QComboBox()
self.op_combo.addItem("前面添加", "prefix")
self.op_combo.addItem("后面添加", "suffix")
self.op_combo.addItem("替换", "replace")
self.op_combo.addItem("删除字符", "delete")
self.param1_label = QLabel("参数1")
self.param1_edit = QLineEdit()
self.param2_label = QLabel("参数2")
self.param2_edit = QLineEdit()
builder_form.addRow(op_label, self.op_combo)
builder_form.addRow(self.param1_label, self.param1_edit)
builder_form.addRow(self.param2_label, self.param2_edit)
add_row = QHBoxLayout()
add_row.addStretch()
self.add_op_btn = QPushButton("添加规则")
add_row.addWidget(self.add_op_btn)
builder_form.addRow(QLabel(""), add_row)
规则列表表格:
self.ops_table = QTableWidget() self.ops_table.setColumnCount(4) self.ops_table.setHorizontalHeaderLabels(["顺序", "类型", "参数1", "参数2"]) self.ops_table.setAlternatingRowColors(True) self.ops_table.setSelectionBehavior(QAbstractItemView.SelectRows) self.ops_table.setSelectionMode(QAbstractItemView.SingleSelection) self.ops_table.setEditTriggers(QAbstractItemView.NoEditTriggers) self.ops_table.horizontalHeader().setSectionResizeMode(0, QHeaderView.ResizeToContents) self.ops_table.horizontalHeader().setSectionResizeMode(1, QHeaderView.ResizeToContents) self.ops_table.horizontalHeader().setSectionResizeMode(2, QHeaderView.Stretch) self.ops_table.horizontalHeader().setSectionResizeMode(3, QHeaderView.Stretch) self.ops_table.verticalHeader().setVisible(False) self.ops_table.setShowGrid(False)
表格下面是几个操作按钮:
- 上移
- 下移
- 删除
- 清空
两个主按钮:
btn_layout = QHBoxLayout()
self.preview_btn = QPushButton("预览")
self.apply_btn = QPushButton("执行重命名")
btn_layout.addStretch()
btn_layout.addWidget(self.preview_btn)
btn_layout.addWidget(self.apply_btn)
main_layout.addLayout(btn_layout)
下方结果表格:
self.table = QTableWidget() self.table.setColumnCount(3) self.table.setHorizontalHeaderLabels(["原目录名", "新目录名", "状态"]) self.table.setAlternatingRowColors(True) self.table.setSelectionBehavior(QAbstractItemView.SelectRows) self.table.setSelectionMode(QAbstractItemView.SingleSelection) self.table.setEditTriggers(QAbstractItemView.NoEditTriggers) self.table.horizontalHeader().setSectionResizeMode(0, QHeaderView.Stretch) self.table.horizontalHeader().setSectionResizeMode(1, QHeaderView.Stretch) self.table.horizontalHeader().setSectionResizeMode(2, QHeaderView.ResizeToContents) self.table.verticalHeader().setVisible(False) self.table.setShowGrid(False)
核心点是让规则可叠加,并按顺序执行。
在窗口类里维护一个列表:
self.operations = []
每条规则是一个字典:
{"mode": "prefix", "p1": "2026_", "p2": ""}
{"mode": "replace", "p1": " ", "p2": "_"}
{"mode": "delete", "p1": "test", "p2": ""}
添加规则时,把当前下拉框和参数输入框的值读出来,做一些校验后塞进 self.operations:
def add_operation(self):
mode = self.op_combo.currentData()
p1 = self.param1_edit.text()
p2 = self.param2_edit.text()
if mode == "replace" and p1 == "":
QMessageBox.warning(self, "提示", "“要替换”不能为空")
return
if mode in ("prefix", "suffix", "delete") and p1 == "":
QMessageBox.warning(self, "提示", "参数不能为空")
return
self.operations.append({"mode": mode, "p1": p1, "p2": p2})
self.refresh_ops_table(select_index=len(self.operations) - 1)
self.param1_edit.setText("")
self.param2_edit.setText("")
refresh_ops_table 把 self.operations 同步到规则表格里:
def refresh_ops_table(self, select_index=None):
self.ops_table.setRowCount(0)
for i, op in enumerate(self.operations):
row = self.ops_table.rowCount()
self.ops_table.insertRow(row)
self.ops_table.setItem(row, 0, QTableWidgetItem(str(i + 1)))
self.ops_table.setItem(row, 1, QTableWidgetItem(self.mode_to_text(op["mode"])))
self.ops_table.setItem(row, 2, QTableWidgetItem(op.get("p1", "")))
self.ops_table.setItem(row, 3, QTableWidgetItem(op.get("p2", "")))
上移 / 下移 / 删除 / 清空其实就是对 self.operations 做 list 操作,然后调用 refresh_ops_table。
给某个目录名应用规则流水线:
def apply_operations(self, name):
new_name = name
for op in self.operations:
new_name = self.get_new_name(op["mode"], new_name, op.get("p1", ""), op.get("p2", ""))
return new_name
get_new_name 处理具体的四种模式:
def get_new_name(self, mode, name, p1, p2):
if mode == "prefix":
if not p1:
return name
return p1 + name
if mode == "suffix":
if not p1:
return name
return name + p1
if mode == "replace":
if not p1:
return name
return name.replace(p1, p2)
if mode == "delete":
if not p1:
return name
return name.replace(p1, "")
return name
预览时,就对目录下的每个子目录名调用一次 apply_operations,得到最终的新名字。
批量改名一定要小心两件事:
- 目标名是否合法(Windows 目录名不能包含
< > : " / | ? *等) - 多个目录是否会改成同一个名字
再进阶一点:有可能存在「互换名字」的情况,比如:
- 原来有
A、B - 规则是把
A改成B,把B改成A
如果直接 os.rename("A", "B"),后面再改 B -> A 会失败,因为 B 已经存在或者冲突。
预览阶段,对每个目录算完新名字后,会先统计一遍数量:
new_name_counts = {}
computed = []
for name in dir_names:
new_name = self.apply_operations(name)
computed.append((name, new_name))
new_name_counts[new_name] = new_name_counts.get(new_name, 0) + 1
然后再逐条填到表格里,同时判断:
if new_name == name:
continue
if not self.is_valid_dirname(new_name):
status_item.setText("冲突:非法名称")
continue
if new_name_counts.get(new_name, 0) > 1:
status_item.setText("冲突:目标重复")
continue
self.rename_tasks.append({"old_path": old_path, "new_path": new_path, "row": row})
is_valid_dirname 简单过滤非法字符:
def is_valid_dirname(self, name):
if name is None:
return False
if name == "":
return False
invalid_chars = set('<>:"/\|?*')
return not any(ch in invalid_chars for ch in name)
执行重命名时采用了一个「两阶段」策略:
- 第一阶段:把所有要改名的目录先重命名到一个临时名字(加上随机后缀)
- 第二阶段:再从这些临时名字统一改成目标新名字
这样就不会出现「A 改成 B,导致原来的 B 被挡住」的问题。
第一阶段:
temp_map = {}
stage1_ok = []
for t in valid_tasks:
old_path = t["old_path"]
row = t["row"]
item = self.table.item(row, 2)
tmp_path = f"{old_path}.__renametmp__{uuid.uuid4().hex}"
try:
os.rename(old_path, tmp_path)
temp_map[tmp_path] = t
stage1_ok.append(tmp_path)
except Exception as e:
msg = f"失败:{e}"
item.setText(msg)
第二阶段:
for tmp_path in stage1_ok:
t = temp_map[tmp_path]
new_path = t["new_path"]
row = t["row"]
item = self.table.item(row, 2)
try:
os.rename(tmp_path, new_path)
item.setText("成功")
except Exception as e:
item.setText(f"失败:{e}")
try:
os.rename(tmp_path, t["old_path"])
except Exception:
pass
这种方式的好处:
- 可以安全处理「互换名字」等复杂情况
- 即便第二阶段失败,也可以尝试把临时目录改回去,尽量保持原状
界面美化主要从三个方面入手:
- 使用 Qt 的
Fusion风格 - 统一字体、背景、卡片式分组
- 按钮和表格的细节样式
设置 Fusion 风格和字体:
def apply_theme(self):
QApplication.setStyle(QStyleFactory.create("Fusion"))
font = QFont()
font.setPointSize(10)
QApplication.setFont(font)
self.setStyleSheet(
"""
QMainWindow { background: #f5f7fb; }
QGroupBox {
background: #ffffff;
border: 1px solid #e2e8f0;
border-radius: 10px;
margin-top: 8px;
}
QGroupBox::title {
subcontrol-origin: margin;
left: 12px;
padding: 0 6px;
color: #334155;
font-weight: 600;
}
QLabel { color: #334155; }
QLineEdit, QComboBox {
background: #ffffff;
border: 1px solid #cbd5e1;
border-radius: 8px;
padding: 7px 10px;
min-height: 20px;
}
QLineEdit:focus, QComboBox:focus { border: 1px solid #4f46e5; }
QPushButton {
background: #4f46e5;
color: #ffffff;
border: none;
border-radius: 10px;
padding: 8px 14px;
font-weight: 600;
}
QPushButton:hover { background: #4338ca; }
QPushButton:pressed { background: #3730a3; }
QPushButton:disabled { background: #94a3b8; color: #f8fafc; }
QTableWidget {
background: #ffffff;
border: 1px solid #e2e8f0;
border-radius: 10px;
selection-background-color: #e0e7ff;
selection-color: #0f172a;
gridline-color: transparent;
}
QHeaderView::section {
background: #f1f5f9;
color: #334155;
border: none;
padding: 8px 10px;
font-weight: 600;
}
QTableWidget::item { padding-left: 8px; padding-right: 8px; }
QStatusBar { background: transparent; color: #475569; }
"""
)
同时,用 QStatusBar 提示当前状态,比如:
- 预览完成:可执行多少条重命名
- 新增了几条规则
self.setStatusBar(self.statusBar())
self.statusBar().showMessage("选择一个目录后点击“预览”,确认无误再执行重命名")

工具完成之后,为了方便在没有 Python 环境的电脑上使用,需要打包成 EXE。这里用的是 PyInstaller。
假设目录结构:
D:测试Github项目61-目录批量改名
├─ renamedir.py
├─ 重命名.png
└─ …
PyInstaller 的 --icon 参数需要 .ico 文件,所以先用 Pillow 转一下:
cd /d "D:测试Github项目61-目录批量改名"
python -m pip install pillow
python -c "from PIL import Image; Image.open('重命名.png').save('重命名.ico')"
这样目录下就会多出一个 重命名.ico。
在同一个目录下执行:
pyinstaller -F -w --clean ^ --name "renamedir" ^ --icon "重命名.ico" ^ "renamedir.py"
参数含义:
-F:单文件 EXE-w:不弹出控制台窗口--clean:打包时清理缓存--name "renamedir":生成的 exe 名叫renamedir.exe--icon "重命名.ico":给 exe 加上自定义图标
打包完成后,会生成:
D:测试Github项目61-目录批量改名
├─ build
├─ dist
│ └─ renamedir.exe
└─ renamedir.spec
双击 distrenamedir.exe 就可以像普通 Windows 程序一样使用了。
这个小工具本质上是一个「批量字符串处理器 + 可视化预览」,换到别的场景也非常通用:
- 把「目录名」换成「文件名」,立即变成批量改文件名工具
- 把规则扩展成:
- 大小写转换(全部大写、全部小写、首字母大写)
- 正则替换(使用
re.sub) - 基于数字的自动编号等
如果继续扩展,可以考虑:
- 增加「递归子目录」选项(深度遍历)
- 增加「撤销」「导出重命名日志」功能
- 把规则保存/加载为配置文件(比如 json),方便复用
以上就是Python结合PyQt5编写一个批量目录重命名工具并打包成EXE的详细内容,更多关于Python批量目录重命名的资料请关注风君子博客其它相关文章!
您可能感兴趣的文章:
- Python文件管理之批量重命名文件详解
- 使用Python脚本轻松实现文件的批量重命名
- Python批量重命名文件夹的方法步骤
- Python如何实现图片批量重命名功能
- Python打造智能批量重命名工具的详细指南
- Python自动化批量重命名与整理文件系统
- Python实现文件批量重命名器