首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 相關知識

Python 批量重命名文件實戰指南

     編輯:PHP 相關知識

Python os 模塊提供 listdir() 遍歷目錄、rename() 重命名文件,配合正則表達式、路徑操作,能高效完成各類批量重命名任務。

核心 API

函數用途關鍵參數
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())

進階場景示例

1. 正則提取編號重命名

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')

2. 遞歸處理子目錄特定文件

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")

3. 安全重命名:避免覆蓋、支持回滾

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()  # 後悔則回滾

常用工具推薦

  • Bulk Rename Utility (Windows GUI,功能極強)
  • rename (Linux 命令行,Perl 正則重命名)
  • rnm (Rust 寫入,跨平台 CLI)
  • Python pathlib (3.4+ 面向對象路徑操作,更現代)

pathlib 現代寫法 (Python 3.4+)

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,配合通用模板與安全機制,能從容應對各種批量重命名需求。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved