Python os 模塊提供 listdir() 遍歷目錄、rename() 重命名文件,配合正則表達式、路徑操作,能高效完成各類批量重命名任務。
| 函數 | 用途 | 關鍵參數 |
|---|---|---|
os.listdir(path) | 列出目錄條目 (文件+子目錄) | 返回列表,不含 . .. |
os.rename(src, dst) | 重命名/移動文件或目錄 | 跨設備可能失敗,Windows 目標存在報錯 |
os.path.join() | 安全拼接路徑 | 自動處理分隔符 |
os.path.isfile() | 判斷是否文件 | 排除目錄 |
import os
def batch_rename(directory, transform_func, dry_run=False):
"""
通用批量重命名
:param directory: 目標目錄
:param transform_func: function(old_name) -> new_name 或 None(跳過)
:param dry_run: True 僅預覽不執行
"""
for fname in os.listdir(directory):
old_path = os.path.join(directory, fname)
if not os.path.isfile(old_path):
continue
new_name = transform_func(fname)
if new_name is None or new_name == fname:
continue
new_path = os.path.join(directory, new_name)
if dry_run:
print(f"[DRY] {fname} -> {new_name}")
else:
try:
os.rename(old_path, new_path)
print(f"[OK] {fname} -> {new_name}")
except OSError as e:
print(f"[ERR] {fname}: {e}")
# 使用示例
if __name__ == '__main__':
# 1. 移除前綴 "IMG_"
batch_rename('/path/to/photos', lambda n: n[4:] if n.startswith('IMG_') else None)
# 2. 添加時間戳前綴
import time
batch_rename('/path/to/logs', lambda n: f"{int(time.time())}_{n}")
# 3. 統一擴展名小寫
batch_rename('/path/to/mixed', lambda n: os.path.splitext(n)[0] + os.path.splitext(n)[1].lower())
import re
def rename_by_pattern(directory, pattern, template):
"""
pattern: 正則,需包含捕獲組
template: 格式字符串,如 "track_{0:03d}.mp3"
"""
regex = re.compile(pattern)
for fname in os.listdir(directory):
if not os.path.isfile(os.path.join(directory, fname)):
continue
match = regex.search(fname)
if match:
groups = match.groups()
new_name = template.format(*groups)
old_path = os.path.join(directory, fname)
new_path = os.path.join(directory, new_name)
if not os.path.exists(new_path):
os.rename(old_path, new_path)
print(f"{fname} -> {new_name}")
# 將 "song (001).mp3" -> "track_001.mp3"
rename_by_pattern('/music', r'\((\d+)\)', 'track_{0}.mp3')
import glob
def rename_in_subdirs(base_dir, file_pattern, name_func):
"""
file_pattern: glob 模式,如 "**/big(*).jpg"
name_func: function(match_groups, original_name) -> new_name
"""
# 遞歸查找
for filepath in glob.glob(os.path.join(base_dir, file_pattern), recursive=True):
if not os.path.isfile(filepath):
continue
dirname = os.path.dirname(filepath)
basename = os.path.basename(filepath)
# 提取匹配組 (需根據 pattern 調整)
# 示例:big(5).jpg -> groups=('5',)
match = re.search(r'big\((\d+)\)', basename)
if match:
new_name = name_func(match.groups(), basename)
new_path = os.path.join(dirname, new_name)
os.rename(filepath, new_path)
print(f"{filepath} -> {new_path}")
# 將 big(5).jpg -> big_5.jpg
rename_in_subdirs('/photos', '**/big(*).jpg',
lambda groups, orig: f"big_{groups[0]}.jpg")
import shutil
import json
from datetime import datetime
class SafeRenamer:
def __init__(self, directory):
self.dir = directory
self.log = []
self.log_file = os.path.join(directory, f'.rename_log_{datetime.now():%Y%m%d_%H%M%S}.json')
def rename(self, old_name, new_name):
old_path = os.path.join(self.dir, old_name)
new_path = os.path.join(self.dir, new_name)
if not os.path.isfile(old_path):
return False, "源文件不存在"
if os.path.exists(new_path):
return False, "目標文件已存在"
try:
os.rename(old_path, new_path)
self.log.append({'old': old_name, 'new': new_name, 'time': datetime.now().isoformat()})
return True, "成功"
except OSError as e:
return False, str(e)
def commit(self):
with open(self.log_file, 'w') as f:
json.dump(self.log, f, indent=2, ensure_ascii=False)
print(f"操作日誌已保存: {self.log_file}")
def rollback(self):
for entry in reversed(self.log):
try:
os.rename(
os.path.join(self.dir, entry['new']),
os.path.join(self.dir, entry['old'])
)
except OSError:
pass
print("已回滾所有操作")
# 使用
renamer = SafeRenamer('/data/files')
for f in os.listdir('/data/files'):
if f.endswith('.tmp'):
renamer.rename(f, f[:-4]) # 移除 .tmp
renamer.commit() # 滿意後提交
# renamer.rollback() # 後悔則回滾
from pathlib import Path
dir_path = Path('/data/photos')
for file in dir_path.iterdir():
if file.is_file() and file.suffix.lower() == '.jpg':
new_name = file.stem.lower() + file.suffix.lower()
if new_name != file.name:
file.rename(file.with_name(new_name))
print(f"{file.name} -> {new_name}")
掌握 Python 文件操作核心 API,配合通用模板與安全機制,能從容應對各種批量重命名需求。