本文目录导读:

我来为您提供一个Python文件批量重命名工具,支持多种命名规则:
基础版本 - 支持多种命名模式
import os
import re
from pathlib import Path
class FileRenamer:
def __init__(self, directory):
"""
初始化
:param directory: 目标文件夹路径
"""
self.directory = Path(directory)
self.files = []
self.changes = []
def scan_files(self, pattern=None, extension=None):
"""
扫描文件
:param pattern: 文件名匹配模式(支持通配符)
:param extension: 文件扩展名过滤
"""
if extension:
self.files = list(self.directory.glob(f'*.{extension}'))
elif pattern:
self.files = list(self.directory.glob(pattern))
else:
self.files = list(self.directory.glob('*'))
# 只保留文件,不包含目录
self.files = [f for f in self.files if f.is_file()]
self.files.sort()
return self.files
def preview(self):
"""预览所有更改"""
print("\n=== 预览修改 ===")
for old_path, new_path in self.changes:
print(f"{old_path.name} -> {new_path.name}")
print(f"总计: {len(self.changes)} 个文件\n")
def execute(self, confirm=True):
"""
执行重命名
:param confirm: 是否确认执行
"""
if confirm:
self.preview()
response = input("确认执行?(y/n): ").lower()
if response != 'y':
print("已取消")
return False
for old_path, new_path in self.changes:
try:
old_path.rename(new_path)
print(f"✓ {old_path.name} -> {new_path.name}")
except Exception as e:
print(f"✗ 重命名 {old_path.name} 失败: {e}")
print(f"\n完成!重命名了 {len(self.changes)} 个文件")
return True
# === 命名规则 ===
def add_prefix(self, prefix):
"""添加前缀"""
self.changes = []
for file in self.files:
new_name = f"{prefix}{file.name}"
self.changes.append((file, file.with_name(new_name)))
return self
def add_suffix(self, suffix):
"""添加后缀(在扩展名之前)"""
self.changes = []
for file in self.files:
stem = file.stem
new_name = f"{stem}{suffix}{file.suffix}"
self.changes.append((file, file.with_name(new_name)))
return self
def replace_text(self, old_text, new_text):
"""替换文本"""
self.changes = []
for file in self.files:
new_name = file.name.replace(old_text, new_text)
self.changes.append((file, file.with_name(new_name)))
return self
def remove_text(self, text):
"""删除文本"""
return self.replace_text(text, "")
def change_extension(self, new_extension):
"""更改扩展名"""
if not new_extension.startswith('.'):
new_extension = f'.{new_extension}'
self.changes = []
for file in self.files:
new_name = f"{file.stem}{new_extension}"
self.changes.append((file, file.with_name(new_name)))
return self
def number_files(self, start=1, padding=2, prefix="", position="prefix"):
"""
按序号重命名
:param start: 起始序号
:param padding: 序号位数(补零)
:param prefix: 文件名前缀
:param position: 序号位置(prefix-在文件名前,suffix-在文件名后)
"""
self.changes = []
for i, file in enumerate(self.files):
num = str(start + i).zfill(padding)
stem = file.stem
ext = file.suffix
if position == "prefix":
new_name = f"{prefix}{num}_{stem}{ext}"
else: # suffix
new_name = f"{stem}_{num}{ext}"
self.changes.append((file, file.with_name(new_name)))
return self
def format_name(self, format_string):
"""
格式化命名
支持的占位符:
{index} - 序号
{name} - 原文件名(不含扩展名)
{ext} - 扩展名
{date} - 当前日期
{time} - 当前时间
"""
from datetime import datetime
now = datetime.now()
self.changes = []
for i, file in enumerate(self.files):
stem = file.stem
ext = file.suffix
new_name = format_string.format(
index=str(i+1).zfill(3),
name=stem,
ext=ext,
date=now.strftime("%Y%m%d"),
time=now.strftime("%H%M%S")
)
self.changes.append((file, file.with_name(new_name)))
return self
def regex_replace(self, pattern, replacement):
"""正则表达式替换"""
self.changes = []
for file in self.files:
new_name = re.sub(pattern, replacement, file.name)
self.changes.append((file, file.with_name(new_name)))
return self
def to_lowercase(self):
"""转为小写"""
self.changes = []
for file in self.files:
new_name = file.name.lower()
self.changes.append((file, file.with_name(new_name)))
return self
def to_uppercase(self):
"""转为大写"""
self.changes = []
for file in self.files:
new_name = file.name.upper()
self.changes.append((file, file.with_name(new_name)))
return self
def remove_spaces(self, replacement="_"):
"""删除空格"""
return self.replace_text(" ", replacement)
def undo(self):
"""撤销上次操作"""
if not self.changes:
print("没有可撤销的操作")
return
changed_files = [(new, old) for old, new in self.changes]
print("\n=== 撤销修改 ===")
for old_path, new_path in changed_files:
try:
if new_path.exists(): # 只撤销存在的文件
new_path.rename(old_path)
print(f"✓ {new_path.name} -> {old_path.name}")
except Exception as e:
print(f"✗ 撤销 {new_path.name} 失败: {e}")
self.changes = []
print("撤销完成")
# === 使用示例 ===
if __name__ == "__main__":
# 创建重命名器实例
renamer = FileRenamer("./test_files") # 替换为你的目标文件夹
# 扫描所有txt文件
renamer.scan_files(extension="txt")
# 应用命名规则(可以链式调用)
renamer.add_prefix("2024_") \
.remove_spaces() \
.to_lowercase()
# 预览修改
renamer.preview()
# 执行重命名
renamer.execute()
图形界面版本 (Tkinter)
import tkinter as tk
from tkinter import ttk, filedialog, messagebox
import os
from pathlib import Path
class BatchRenamerGUI:
def __init__(self, root):
self.root = root
self.root.title("批量文件重命名工具")
self.root.geometry("700x500")
self.directory = ""
self.files = []
self.changes = []
self.setup_ui()
def setup_ui(self):
# 主框架
main_frame = ttk.Frame(self.root, padding="10")
main_frame.grid(row=0, column=0, sticky=(tk.W, tk.E, tk.N, tk.S))
# 文件夹选择
ttk.Label(main_frame, text="选择文件夹:").grid(row=0, column=0, sticky=tk.W)
self.dir_var = tk.StringVar()
ttk.Entry(main_frame, textvariable=self.dir_var, width=50).grid(row=0, column=1, padx=5)
ttk.Button(main_frame, text="浏览", command=self.browse_folder).grid(row=0, column=2)
# 文件过滤
ttk.Label(main_frame, text="文件类型:").grid(row=1, column=0, sticky=tk.W, pady=5)
self.ext_var = tk.StringVar(value="所有文件")
ext_combo = ttk.Combobox(main_frame, textvariable=self.ext_var, width=20)
ext_combo['values'] = ('所有文件', '.txt', '.jpg', '.png', '.pdf', '.docx', '.xlsx', '.csv')
ext_combo.grid(row=1, column=1, sticky=tk.W, pady=5)
ttk.Button(main_frame, text="扫描文件", command=self.scan_files).grid(row=1, column=2, pady=5)
# 文件列表
ttk.Label(main_frame, text="文件列表:").grid(row=2, column=0, sticky=tk.W, pady=5)
self.file_listbox = tk.Listbox(main_frame, height=10, width=80)
self.file_listbox.grid(row=3, column=0, columnspan=3, pady=5)
# 滚动条
scrollbar = ttk.Scrollbar(main_frame, orient=tk.VERTICAL, command=self.file_listbox.yview)
scrollbar.grid(row=3, column=3, sticky=(tk.N, tk.S))
self.file_listbox.configure(yscrollcommand=scrollbar.set)
# 命名规则框架
rules_frame = ttk.LabelFrame(main_frame, text="命名规则", padding="5")
rules_frame.grid(row=4, column=0, columnspan=3, pady=10, sticky=(tk.W, tk.E))
# 添加前缀
ttk.Label(rules_frame, text="添加前缀:").grid(row=0, column=0, padx=5)
self.prefix_var = tk.StringVar()
ttk.Entry(rules_frame, textvariable=self.prefix_var, width=15).grid(row=0, column=1)
ttk.Button(rules_frame, text="应用", command=lambda: self.apply_rule("prefix")).grid(row=0, column=2, padx=5)
# 添加后缀
ttk.Label(rules_frame, text="添加后缀:").grid(row=0, column=3, padx=5)
self.suffix_var = tk.StringVar()
ttk.Entry(rules_frame, textvariable=self.suffix_var, width=15).grid(row=0, column=4)
ttk.Button(rules_frame, text="应用", command=lambda: self.apply_rule("suffix")).grid(row=0, column=5, padx=5)
# 替换文本
ttk.Label(rules_frame, text="替换:").grid(row=1, column=0, padx=5, pady=5)
self.replace_old_var = tk.StringVar()
ttk.Entry(rules_frame, textvariable=self.replace_old_var, width=10).grid(row=1, column=1, pady=5)
ttk.Label(rules_frame, text="→").grid(row=1, column=2)
self.replace_new_var = tk.StringVar()
ttk.Entry(rules_frame, textvariable=self.replace_new_var, width=10).grid(row=1, column=3, pady=5)
ttk.Button(rules_frame, text="替换", command=lambda: self.apply_rule("replace")).grid(row=1, column=4, pady=5)
# 序号重命名
ttk.Label(rules_frame, text="序号:").grid(row=2, column=0, padx=5)
self.num_start_var = tk.StringVar(value="1")
ttk.Spinbox(rules_frame, from_=0, to=999, textvariable=self.num_start_var, width=5).grid(row=2, column=1)
ttk.Label(rules_frame, text="位数:").grid(row=2, column=2)
self.num_padding_var = tk.StringVar(value="2")
ttk.Spinbox(rules_frame, from_=1, to=5, textvariable=self.num_padding_var, width=5).grid(row=2, column=3)
ttk.Button(rules_frame, text="编号", command=lambda: self.apply_rule("number")).grid(row=2, column=4)
# 操作按钮
button_frame = ttk.Frame(main_frame)
button_frame.grid(row=5, column=0, columnspan=3, pady=10)
ttk.Button(button_frame, text="预览修改", command=self.preview_changes).pack(side=tk.LEFT, padx=5)
ttk.Button(button_frame, text="执行重命名", command=self.execute_rename).pack(side=tk.LEFT, padx=5)
ttk.Button(button_frame, text="重置", command=self.reset).pack(side=tk.LEFT, padx=5)
# 状态栏
self.status_var = tk.StringVar(value="就绪")
status_bar = ttk.Label(main_frame, textvariable=self.status_var, relief=tk.SUNKEN, anchor=tk.W)
status_bar.grid(row=6, column=0, columnspan=3, sticky=(tk.W, tk.E), pady=5)
def browse_folder(self):
directory = filedialog.askdirectory()
if directory:
self.dir_var.set(directory)
self.scan_files()
def scan_files(self):
directory = self.dir_var.get()
if not directory:
messagebox.showerror("错误", "请选择文件夹")
return
self.files = []
self.file_listbox.delete(0, tk.END)
ext = self.ext_var.get()
if ext == "所有文件":
pattern = "*"
else:
pattern = f"*{ext}"
for file in Path(directory).glob(pattern):
if file.is_file():
self.files.append(file)
self.file_listbox.insert(tk.END, file.name)
self.status_var.set(f"找到 {len(self.files)} 个文件")
def apply_rule(self, rule_type):
if not self.files:
messagebox.showerror("错误", "请先扫描文件")
return
from datetime import datetime
self.changes = []
for i, file in enumerate(self.files):
stem = file.stem
ext = file.suffix
if rule_type == "prefix":
new_name = f"{self.prefix_var.get()}{file.name}"
elif rule_type == "suffix":
new_name = f"{stem}{self.suffix_var.get()}{ext}"
elif rule_type == "replace":
new_name = file.name.replace(self.replace_old_var.get(), self.replace_new_var.get())
elif rule_type == "number":
start = int(self.num_start_var.get())
padding = int(self.num_padding_var.get())
num = str(start + i).zfill(padding)
new_name = f"{num}_{file.name}"
else:
continue
self.changes.append((file, file.with_name(new_name)))
self.status_var.set(f"已应用规则,待处理 {len(self.changes)} 个文件")
self.preview_changes()
def preview_changes(self):
if not self.changes:
messagebox.showinfo("提示", "没有待处理的更改")
return
preview_text = "=== 预览修改 ===\n\n"
for old, new in self.changes:
preview_text += f" {old.name}\n → {new.name}\n\n"
preview_text += f"\n总计: {len(self.changes)} 个文件"
messagebox.showinfo("预览修改", preview_text)
def execute_rename(self):
if not self.changes:
messagebox.showerror("错误", "没有待执行的更改")
return
if not messagebox.askyesno("确认", f"确定要重命名 {len(self.changes)} 个文件吗?"):
return
success = 0
failed = 0
for old, new in self.changes:
try:
if not new.exists(): # 避免覆盖已有文件
old.rename(new)
success += 1
else:
failed += 1
messagebox.showwarning("警告", f"目标文件已存在: {new.name}")
except Exception as e:
failed += 1
print(f"重命名失败: {e}")
self.status_var.set(f"完成!成功: {success}, 失败: {failed}")
self.scan_files() # 刷新文件列表
self.changes = []
def reset(self):
self.changes = []
self.status_var.set("已重置")
if __name__ == "__main__":
root = tk.Tk()
app = BatchRenamerGUI(root)
root.mainloop()
命令行版本
#!/bin/bash
# file_renamer.sh - 命令行批量重命名工具
# 使用方法
usage() {
echo "批量文件重命名工具"
echo "用法: $0 [选项]"
echo ""
echo "选项:"
echo " -d DIR 目标文件夹 (默认: 当前目录)"
echo " -e EXT 文件扩展名过滤"
echo " -p PREFIX 添加前缀"
echo " -s SUFFIX 添加后缀"
echo " -r OLD NEW 替换文本"
echo " -n 序号重命名"
echo " -l 转为小写"
echo " -u 转为大写"
echo " --dry-run 预览模式"
echo ""
echo "示例:"
echo " $0 -d ./images -e jpg -p photo_"
echo " $0 -e txt -r 'old' 'new'"
echo " $0 -e pdf -n --dry-run"
}
# 解析参数
DIR="."
EXT=""
PREFIX=""
SUFFIX=""
REPLACE_OLD=""
REPLACE_NEW=""
NUMBER=false
LOWERCASE=false
UPPERCASE=false
DRY_RUN=false
while [[ $# -gt 0 ]]; do
case $1 in
-d) DIR="$2"; shift 2 ;;
-e) EXT="$2"; shift 2 ;;
-p) PREFIX="$2"; shift 2 ;;
-s) SUFFIX="$2"; shift 2 ;;
-r) REPLACE_OLD="$2"; REPLACE_NEW="$3"; shift 3 ;;
-n) NUMBER=true; shift ;;
-l) LOWERCASE=true; shift ;;
-u) UPPERCASE=true; shift ;;
--dry-run) DRY_RUN=true; shift ;;
-h|--help) usage; exit 0 ;;
*) echo "未知选项: $1"; usage; exit 1 ;;
esac
done
# 扫描文件
if [[ -n "$EXT" ]]; then
files=("$DIR"/*."$EXT")
else
files=("$DIR"/*)
fi
count=0
for file in "${files[@]}"; do
if [[ -f "$file" ]]; then
dir=$(dirname "$file")
basename=$(basename "$file")
filename="${basename%.*}"
extension="${basename##*.}"
newname="$basename"
# 应用规则
[[ -n "$PREFIX" ]] && newname="$PREFIX$newname"
[[ -n "$SUFFIX" ]] && newname="${filename}${SUFFIX}.${extension}"
[[ -n "$REPLACE_OLD" ]] && newname="${newname//$REPLACE_OLD/$REPLACE_NEW}"
if [[ "$LOWERCASE" == true ]]; then
newname=$(echo "$newname" | tr '[:upper:]' '[:lower:]')
fi
if [[ "$UPPERCASE" == true ]]; then
newname=$(echo "$newname" | tr '[:lower:]' '[:upper:]')
fi
if [[ "$NUMBER" == true ]]; then
count=$((count + 1))
num=$(printf "%02d" $count)
newname="${num}_${filename}.${extension}"
fi
# 预览或执行
if [[ "$DRY_RUN" == true ]]; then
echo "[预览] $basename -> $newname"
else
if [[ "$basename" != "$newname" ]]; then
mv "$file" "$dir/$newname"
echo "[执行] $basename -> $newname"
fi
fi
fi
done
echo "处理完成!"
使用方法
Python版本:
- 创建Python文件并运行
- 修改
directory为你的目标文件夹 - 调用不同的重命名方法
图形界面版本:
- 运行程序
- 选择文件夹
- 选择文件类型
- 应用不同的命名规则
- 预览并执行
命令行版本:
# 示例 ./file_renamer.sh -d ./photos -e jpg -p "vacation_" ./file_renamer.sh -e txt -r "old" "new" ./file_renamer.sh -e pdf -n --dry-run
支持的功能
- ✅ 添加前缀/后缀
- ✅ 替换/删除文本
- ✅ 序号重命名
- ✅ 大小写转换
- ✅ 正则表达式替换
- ✅ 撤销操作
- ✅ 预览修改
- ✅ 文件类型过滤
- ✅ 图形界面(可选)
需要更多定制功能或改进,请告诉我!
标签: 文件批量重命名工具
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播