当前位置: 代码网 > it编程>前端脚本>Python > 通过Python实现批量修改文件名前后缀功能

通过Python实现批量修改文件名前后缀功能

2025年05月30日 Python 我要评论
功能实现要实现的功能其实很简单,通过python代码获取文件夹的路径,通过循环处理该文件夹中所有文件的名称,之后对文件名进行更新即可,整个撰写代码是通过人工加上ai的方式进行的。添加添加前后缀,直接对

功能实现

要实现的功能其实很简单,通过python代码获取文件夹的路径,通过循环处理该文件夹中所有文件的名称,之后对文件名进行更新即可,整个撰写代码是通过人工加上ai的方式进行的。

添加

添加前后缀,直接对原始的字符串进行拼接即可,中间通过分割符来分割,对于添加的字符串不论中文还是英文都需要满足windows系统文件命名的规范,项目中通过ai实现了验证过程,但是可能还是不完善。

# 添加前缀 
new_base = f"{content}{selected_separator}{base_name}"
# 添加后缀
new_base = f"{base_name}{selected_separator}{content}"

 重命名操作

# 执行重命名操作
try:
    os.replace(file_path, new_path)  # 自动覆盖已存在的文件
    print(f"成功重命名:{filename} -> {new_name}")
except exception as e:
    messagebox.showerror("重命名错误",
                         f"无法重命名 {filename}:\n{str(e)}\n"
                          "可能原因:\n"
                          "1. 文件正在被其他程序使用\n"
                          "2. 没有写入权限\n"
                          "3. 文件名包含系统保留字符")
     break  # 遇到错误中止处理

删除

删除前后缀即对字符串进行分割操作。 

# 删除前缀使用split(从左分割)
parts = base_name.split(f"{content}{selected_separator}", 1)
# 删除后缀使用rsplit(从右分割)
parts = base_name.rsplit(f"{selected_separator}{content}", 1)

没想到这么快在使用过程中出现问题 ,这个直接分割可能出现中间截取的情况,比如“专题01 物质的组成、性质、分类与化学用语(讲)(原卷+解析版)”这个文件名,如果我是要删除后缀“ 物质”,这个肯定是无法找到的,但是如果是截取,他则会只保留“专题01”。

修改代码如下:

            elif selected_mode == "删除前缀":
                # 格式验证:必须包含分割符且分割符在content之后
                if base_name.startswith(f"{content}{selected_separator}"):
                    # 计算前缀长度时考虑中文等宽字符问题
                    prefix_length = len(content) + len(selected_separator)
                    new_base = base_name[prefix_length:]
 
                    # 增加空文件名校验
                    if not new_base:
                        print(f"警告:删除前缀后文件名为空,跳过 {filename}")
                        continue
                else:
                    print(f"未找到匹配前缀:{content}{selected_separator}")
                    continue
            elif selected_mode == "删除后缀":
                # 格式验证:必须严格以【分隔符+内容】结尾
                suffix_pattern = f"{selected_separator}{content}"
                if base_name.endswith(suffix_pattern):
                    # 计算后缀长度(考虑多语言字符)
                    suffix_length = len(suffix_pattern)
                    new_base = base_name[:-suffix_length]
 
                    # 空文件名防御机制
                    if not new_base.strip():  # 处理纯空白字符情况
                        print(f"危险操作:删除后缀后文件名为空,跳过 {filename}")
                        continue
                else:
                    print(f"未找到匹配后缀:{suffix_pattern}")
                    continue

当然在删除前还需要对文件名进行验证,看是否有符合的前后缀以及是否和其他文件名冲突。

# 前缀验证
if f"{content}{selected_separator}" in base_name:

 不论是添加还是删除操作都需要检测文件名是否冲突。

# 检测文件名冲突
if os.path.exists(new_path):
    # 弹出二次确认对话框
    confirm = messagebox.askyesno(
        "确认覆盖",
        f"文件 '{new_name}' 已存在!\n"
        f"原文件:{filename}\n"
        f"新文件:{new_name}\n\n"
        "是否覆盖已有文件?",
        icon='warning'
     )
     if not confirm:
         print(f"跳过已存在文件:{new_name}")
         continue

图形界面

定义界面

对于这些框架的代码,使用ai还是比较容易实现,就是调试起来有点麻烦,不能无脑丢给ai,还需要自己进行分析,通过电脑界面来对窗口的界面和位置进行设置。

# 定义界面框架
class frame:
    # 创建窗口
    window = tk.tk()
    # 在frame类初始化前添加样式配置代码
    style = ttk.style()
    # 设置主题为clam
    style.theme_use('clam')
    # 配置下拉框主体样式
    style.configure('centered.tcombobox', justify="center", foreground="#2c3e50",
                    fieldbackground="white", padding=(0, 15), anchor="center", state="readonly")
    # 配置下拉列表的样式
    style.configure('centered.tcombobox.listbox', foreground="#2c3e50",
                    rowheight=30, anchor="center")
    # 设置标题
    window.title("文件批量重命名工具")
    # 获取屏幕大小
    screen_width = window.winfo_screenwidth()
    screen_height = window.winfo_screenheight()
    # 计算所需窗口的相对大小
    relative_width = int(screen_width * 0.5)
    relative_height = int(screen_height * 0.5)
    # 计算窗口位于屏幕中央的坐标
    relative_x = (screen_width - relative_width) // 2
    relative_y = (screen_height - relative_height) // 2
    # 应用窗口尺寸和位置(格式:宽度x高度+x坐标+y坐标)
    window.geometry(f"{relative_width}x{relative_height}+{relative_x}+{relative_y}")
    # 应用组件
    module(window)
    # 运行窗口
    window.mainloop()

定义组件

主要就是涉及到了文本框、按钮和下拉框的布局,需要对文本框修改成只读的属性,文件夹路径

操作模式和分割符就没有进行是否规范的判断。

def module(window):
    global path_entry, mode_var, separator_var  # 声明全局变量(因为后续在其他函数中需要使用到这些参数)
    # 初始化默认值
    mode_var = tk.stringvar(value="添加前缀")
    separator_var = tk.stringvar(value=" _下划线")
    #########################################################################################################
    # 新增创建路径选择容器(顶部区域)
    path_frame = tk.frame(window)
    path_frame.pack(side=tk.top, pady=20)
    # 创建只读文本框
    path_entry = tk.entry(path_frame, width=65, font=("仿宋", 12, "bold"), state="readonly",
                          readonlybackground="white")
    path_entry.pack(side=tk.left, padx=5, ipady=25)
    # 创建浏览按钮
    browse_button = tk.button(path_frame, text="获取文件夹名", width=100, height=2, bg="#2196f3", fg="white",
                              font=("仿宋", 18, "bold"), command=lambda: browse_folder(path_entry))
    browse_button.pack(side=tk.right, padx=5)
    #########################################################################################################
    # 增加操作模式选择区域
    mode_frame = tk.frame(window)
    mode_frame.pack(fill=tk.x, pady=20)
    # 模式选择标签
    mode_label = tk.label(mode_frame, text="操作模式:", font=("仿宋", 28, "bold"), width=15)
    mode_label.pack(side=tk.left, padx=5)
    # 下拉框选项数据
    mode_options = ["添加前缀", "添加后缀", "删除前缀", "删除后缀"]
    # 创建下拉框(要用textvariable=mode_var绑定数据,不然不会更新)
    mode_combobox = ttk.combobox(mode_frame, values=mode_options, width=30, style='centered.tcombobox',
                                 justify="center", state="readonly", font=("仿宋", 28, "bold"), textvariable=mode_var)
    mode_combobox.pack(side=tk.left, padx=15)
    mode_combobox.current(0)  # 设置默认选中
    #########################################################################################################
    # 增加常见分割符区域
    mode_frame = tk.frame(window)
    mode_frame.pack(fill=tk.x, pady=20)
    # 模式选择标签
    mode_label = tk.label(mode_frame, text="常见分割符", font=("仿宋", 28, "bold"), width=15, anchor="center")
    mode_label.pack(side=tk.left, padx=5)
    # 下拉框选项数据
    mode_options = ["_下划线", "-连字符", ".点号", " 空格"]
    # 创建下拉框(新增绑定textvariable=separator_var)
    mode_combobox = ttk.combobox(mode_frame, values=mode_options, width=30, style='centered.tcombobox',
                                 font=("仿宋", 28, "bold"), state="readonly", justify="center",
                                 textvariable=separator_var)
    mode_combobox.pack(side=tk.left, padx=15)
    mode_combobox.current(0)  # 设置默认选中
    #########################################################################################################
    # 给界面添加确认和取消的按钮
    # 创建按钮容器框架(实现更灵活的布局控制)
    button_frame = tk.frame(window)
    # 固定在窗口底部并设置纵向间距
    button_frame.pack(side=tk.bottom, pady=20)
    # 创建确认和取消按钮
    confirm_button = tk.button(button_frame, text="确认", width=12, height=2, bg="#4caf50", fg="white",
                               font=("仿宋", 18, "bold"), command=lambda: on_confirm())  # 绑定确认事件处理
    cancel_button = tk.button(button_frame, text="取消", width=12, height=2, bg="#f44336", fg="white",
                              font=("仿宋", 18, "bold"),
                              command=lambda: window.destroy())  # 直接绑定关闭窗口的事件
    # 确认按钮(添加pack布局)
    confirm_button.pack(side=tk.left, padx=10, ipady=5)
    # 取消按钮(添加pack布局)
    cancel_button.pack(side=tk.right, padx=10, ipady=5)

系统界面如下图所示

完整代码

完整的代码如下:

import os
import tkinter as tk
from tkinter import filedialog
from tkinter import ttk
from tkinter import messagebox
from tkinter import simpledialog
 
 
# 验证文件名是否符合windows规范(中文增强版)
# 修改现有is_valid_filename函数
def is_valid_filename(text: str) -> bool:
    # 非法字符检测(保持原逻辑)
    illegal_chars = set('\\/:*?"<>|')
    if any(char in illegal_chars for char in text):
        return false
 
    # 保留名称检测(保持原逻辑)
    reserved_names = {
        'con', 'prn', 'aux', 'nul', 'com1', 'com2', 'com3',
        'com4', 'com5', 'com6', 'com7', 'com8', 'com9',
        'lpt1', 'lpt2', 'lpt3', 'lpt4', 'lpt5', 'lpt6',
        'lpt7', 'lpt8', 'lpt9'
    }
    if text.upper() in reserved_names:
        return false
 
    # 增强中文处理
    # 1. 检查全角字符是否包含非法字符(中文输入法可能输入全角字符)
    fullwidth_illegal = set('\/:*?"<>|')  # 全角非法字符
    if any(char in fullwidth_illegal for char in text):
        return false
 
    # 2. 增强长度检测(基于字符数而非字节数)
    # windows允许最多255个字符(包括中文)
    if len(text) > 255:
        return false
 
    # 3. 检查首尾空格(中文文件名常见问题)
    if text.strip() != text:
        return false
 
    # 4. 检查末尾点号(.test.txt. 这种形式)
    if text.endswith('.') or text.startswith('.'):
        return false
 
    return true
 
 
# 用文本框获取添加或者删除的字符串
def gettextbox(parent_window=none):
    # 通过全局控件获取父窗口
    global path_entry  # 声明使用全局路径输入框
    parent_window = path_entry.winfo_toplevel()  # 获取输入框所在的顶级窗口
 
    # 添加循环输入机制
    while true:
        content = simpledialog.askstring(
            "输入内容",
            "请输入要添加的字符串(不能包含 \\/:*?\"<>| 等非法字符):",  # 添加提示
            parent=parent_window
        )
        print("输入:", content)
        # 用户取消输入
        if content is none:
            return none
 
        # 验证逻辑
        if not content:
            messagebox.showerror("错误", "输入不能为空!")
        elif not is_valid_filename(content):
            messagebox.showerror("错误",
                                 f"文件名不合法!\n"
                                 f"1. 请勿使用:\\ / : * ? \" < > | 及其全角形式\n"
                                 f"2. 不要使用con、prn等保留名称\n"
                                 f"3. 长度不超过255字符(当前:{len(content)})\n"
                                 f"4. 首尾不能有空格\n"
                                 f"5. 不能以点号开头或结尾")
        else:
            return content  # 合法输入退出循环
 
 
# 新增文件夹浏览函数
def browse_folder(entry_widget):
    """打开文件夹选择对话框"""
    folder_path = filedialog.askdirectory(title='请选择要处理的文件夹')
    if folder_path:
        # 清空并更新文本框内容
        entry_widget.config(state='normal')
        entry_widget.delete(0, tk.end)
        entry_widget.insert(0, folder_path)
        entry_widget.config(state='readonly')
        # 可选:自动滚动到末尾
        entry_widget.xview_moveto(1)
 
 
# 定义确认事件处理
def on_confirm():
    # print("确认")
    # 获取所有输入数据
    folder_path = path_entry.get()
    selected_mode = mode_var.get()
    selected_separator = separator_var.get()[0]  # 只要前一个英文字符即可
 
    # 验证数据完整性
    if not folder_path:
        messagebox.showerror("警告", "请先选择文件夹!")
        # 选择文件夹名
        browse_folder(path_entry)
        return
 
    # 打印结果
    print(f"文件夹路径:{folder_path}")
    print(f"操作模式:{selected_mode}")
    print(f"分隔符:{selected_separator}")
 
    # 获取要添加或者删除的文字,需要在循环外就确认了,因为只需要确认一次即可
    content = gettextbox()
 
    # 输入为none不能继续运行了,否则会把none当做字符串进行拼接
    if content is none:
        return
    # 新增文件处理逻辑(listdir获取文件夹中所有文件和文件夹名称组成的列表)
    for filename in os.listdir(folder_path):
        # 获取文件路径(join拼接路径)
        file_path = os.path.join(folder_path, filename)
        if os.path.isfile(file_path):
            # 打印文件路径
            # print(f"正在处理文件:{file_path}")
            # 分割文件名和拓展名
            base_name, ext = os.path.splitext(filename)
            # 根据模式处理文件名
            if selected_mode == "添加前缀":
                # 直接进行拼接操作
                new_base = f"{content}{selected_separator}{base_name}"
                # print(new_base)
            elif selected_mode == "添加后缀":
                new_base = f"{base_name}{selected_separator}{content}"
            elif selected_mode == "删除前缀":
                # 格式验证:必须包含分割符且分割符在content之后
                if base_name.startswith(f"{content}{selected_separator}"):
                    # 计算前缀长度时考虑中文等宽字符问题
                    prefix_length = len(content) + len(selected_separator)
                    new_base = base_name[prefix_length:]
 
                    # 增加空文件名校验
                    if not new_base:
                        print(f"警告:删除前缀后文件名为空,跳过 {filename}")
                        continue
                else:
                    print(f"未找到匹配前缀:{content}{selected_separator}")
                    continue
            elif selected_mode == "删除后缀":
                # 格式验证:必须严格以【分隔符+内容】结尾
                suffix_pattern = f"{selected_separator}{content}"
                if base_name.endswith(suffix_pattern):
                    # 计算后缀长度(考虑多语言字符)
                    suffix_length = len(suffix_pattern)
                    new_base = base_name[:-suffix_length]
 
                    # 空文件名防御机制
                    if not new_base.strip():  # 处理纯空白字符情况
                        print(f"危险操作:删除后缀后文件名为空,跳过 {filename}")
                        continue
                else:
                    print(f"未找到匹配后缀:{suffix_pattern}")
                    continue
 
        # 拼接新的文件名
        new_name = f"{new_base}{ext}"
        # 拼接新的文件路径
        new_path = os.path.join(folder_path, new_name)
        # 检测文件名冲突
        if os.path.exists(new_path):
            # 弹出二次确认对话框
            confirm = messagebox.askyesno(
                "确认覆盖",
                f"文件 '{new_name}' 已存在!\n"
                f"原文件:{filename}\n"
                f"新文件:{new_name}\n\n"
                "是否覆盖已有文件?",
                icon='warning'
            )
            if not confirm:
                print(f"跳过已存在文件:{new_name}")
                continue
        # 执行重命名操作
        try:
            os.replace(file_path, new_path)  # 自动覆盖已存在的文件
            print(f"成功重命名:{filename} -> {new_name}")
        except exception as e:
            messagebox.showerror("重命名错误",
                                 f"无法重命名 {filename}:\n{str(e)}\n"
                                 "可能原因:\n"
                                 "1. 文件正在被其他程序使用\n"
                                 "2. 没有写入权限\n"
                                 "3. 文件名包含系统保留字符")
            break  # 遇到错误中止处理
 
 
# 定义界面展示的组件
def module(window):
    global path_entry, mode_var, separator_var  # 声明全局变量(因为后续在其他函数中需要使用到这些参数)
    # 初始化默认值
    mode_var = tk.stringvar(value="添加前缀")
    separator_var = tk.stringvar(value=" _下划线")
    #########################################################################################################
    # 新增创建路径选择容器(顶部区域)
    path_frame = tk.frame(window)
    path_frame.pack(side=tk.top, pady=20)
    # 创建只读文本框
    path_entry = tk.entry(path_frame, width=65, font=("仿宋", 12, "bold"), state="readonly",
                          readonlybackground="white")
    path_entry.pack(side=tk.left, padx=5, ipady=25)
    # 创建浏览按钮
    browse_button = tk.button(path_frame, text="获取文件夹名", width=100, height=2, bg="#2196f3", fg="white",
                              font=("仿宋", 18, "bold"), command=lambda: browse_folder(path_entry))
    browse_button.pack(side=tk.right, padx=5)
    #########################################################################################################
    # 增加操作模式选择区域
    mode_frame = tk.frame(window)
    mode_frame.pack(fill=tk.x, pady=20)
    # 模式选择标签
    mode_label = tk.label(mode_frame, text="操作模式:", font=("仿宋", 28, "bold"), width=15)
    mode_label.pack(side=tk.left, padx=5)
    # 下拉框选项数据
    mode_options = ["添加前缀", "添加后缀", "删除前缀", "删除后缀"]
    # 创建下拉框(要用textvariable=mode_var绑定数据,不然不会更新)
    mode_combobox = ttk.combobox(mode_frame, values=mode_options, width=30, style='centered.tcombobox',
                                 justify="center", state="readonly", font=("仿宋", 28, "bold"), textvariable=mode_var)
    mode_combobox.pack(side=tk.left, padx=15)
    mode_combobox.current(0)  # 设置默认选中
    #########################################################################################################
    # 增加常见分割符区域
    mode_frame = tk.frame(window)
    mode_frame.pack(fill=tk.x, pady=20)
    # 模式选择标签
    mode_label = tk.label(mode_frame, text="常见分割符", font=("仿宋", 28, "bold"), width=15, anchor="center")
    mode_label.pack(side=tk.left, padx=5)
    # 下拉框选项数据
    mode_options = ["_下划线", "-连字符", ".点号", " 空格"]
    # 创建下拉框(新增绑定textvariable=separator_var)
    mode_combobox = ttk.combobox(mode_frame, values=mode_options, width=30, style='centered.tcombobox',
                                 font=("仿宋", 28, "bold"), state="readonly", justify="center",
                                 textvariable=separator_var)
    mode_combobox.pack(side=tk.left, padx=15)
    mode_combobox.current(0)  # 设置默认选中
    #########################################################################################################
    # 给界面添加确认和取消的按钮
    # 创建按钮容器框架(实现更灵活的布局控制)
    button_frame = tk.frame(window)
    # 固定在窗口底部并设置纵向间距
    button_frame.pack(side=tk.bottom, pady=20)
    # 创建确认和取消按钮
    confirm_button = tk.button(button_frame, text="确认", width=12, height=2, bg="#4caf50", fg="white",
                               font=("仿宋", 18, "bold"), command=lambda: on_confirm())  # 绑定确认事件处理
    cancel_button = tk.button(button_frame, text="取消", width=12, height=2, bg="#f44336", fg="white",
                              font=("仿宋", 18, "bold"),
                              command=lambda: window.destroy())  # 直接绑定关闭窗口的事件
    # 确认按钮(添加pack布局)
    confirm_button.pack(side=tk.left, padx=10, ipady=5)
    # 取消按钮(添加pack布局)
    cancel_button.pack(side=tk.right, padx=10, ipady=5)
 
 
# 定义界面框架
class frame:
    # 创建窗口
    window = tk.tk()
    # 在frame类初始化前添加样式配置代码
    style = ttk.style()
    # 设置主题为clam
    style.theme_use('clam')
    # 配置下拉框主体样式
    style.configure('centered.tcombobox', justify="center", foreground="#2c3e50",
                    fieldbackground="white", padding=(0, 15), anchor="center", state="readonly")
    # 配置下拉列表的样式
    style.configure('centered.tcombobox.listbox', foreground="#2c3e50",
                    rowheight=30, anchor="center")
    # 设置标题
    window.title("文件批量重命名工具")
    # 获取屏幕大小
    screen_width = window.winfo_screenwidth()
    screen_height = window.winfo_screenheight()
    # 计算所需窗口的相对大小
    relative_width = int(screen_width * 0.5)
    relative_height = int(screen_height * 0.5)
    # 计算窗口位于屏幕中央的坐标
    relative_x = (screen_width - relative_width) // 2
    relative_y = (screen_height - relative_height) // 2
    # 应用窗口尺寸和位置(格式:宽度x高度+x坐标+y坐标)
    window.geometry(f"{relative_width}x{relative_height}+{relative_x}+{relative_y}")
    # 应用组件
    module(window)
    # 运行窗口
    window.mainloop()
 
 
def main():
    # 创建窗口
    frame()
 
 
if __name__ == "__main__":
    main()

测试

原始文件名

选择“操作模式”以及“常见分割符”,后点击“确认”按钮,在输入框中输入需要添加或者删除的字符串。

pycharm中的输出:

结果如下图所示: 

添加后缀操作:

这里之前出现了一个问题,如果文本框没有输入的话,他会返回none,然后把none当做字符串进行拼接,这里需要避免这种情况。

# 输入为none不能继续运行了,否则会把none当做字符串进行拼接
if content is none:
    return

对于后续还可以通过修改代码批量修改文件的扩展名。

以上就是通过python实现批量修改文件名前后缀功能的详细内容,更多关于python批量修改文件名前后缀的资料请关注代码网其它相关文章!

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2025  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com