利用Python写一个配置文件修改工具

最近新上公司新产品项目,服务端部署完成后,医院安全管理部署需要调整服务器IP地址,这就涉及到重新配置服务器程序相关配置。由于配置文件分散且手动修改工作量大,考量到后续如有同样需求,捡起前期学过的Python基础,准备用python写一个处理工具。以下简单记录一下过程。

1、windows安装python环境

在 Windows 系统上安装 Python 环境的步骤如下:

步骤 1: 下载 Python 安装包

  1. 打开 Python 官方网站
  2. 点击页面顶部的“Downloads”链接,选择适合 Windows 的最新版本(通常是推荐的版本)。

步骤 2: 运行安装程序

  1. 下载完成后,双击运行下载的安装包(例如 python-3.x.x.exe)。
  2. 在安装向导中,确保选中“Add Python to PATH”复选框,然后点击“Install Now”进行快速安装。
  3. 如果你需要自定义安装选项,可以选择“Customize installation”,根据需要选择相应的选项。

步骤 3: 验证 Python 安装

  1. 安装完成后,打开命令提示符(可以按 Win + R,然后输入 cmd 并回车)。
  2. 在命令提示符中输入以下命令,检查 Python 是否安装成功:
python --version

或者:

python -V

如果安装成功,你会看到 Python 的版本号。

  1. 你还可以检查 pip(Python 包管理工具)的安装情况:
pip --version

步骤 4: 设置 Python 开发环境(可选)

  1. 安装 IDE:建议安装一个集成开发环境(IDE),如 PyCharm、Visual Studio Code 或 Anaconda,来方便编写和运行 Python 代码。
  2. 安装常用库:通过 pip 安装一些常用库,例如:
pip install  chardet pyinstaller tkinter

注意事项

  • 确保你的计算机连接到互联网,以便下载安装包和后续的库。
  • 如果在安装过程中遇到问题,可以参考官方文档或社区的帮助资源。

通过这些步骤,你就可以在 Windows 系统上成功安装 Python 环境并开始编程了。

2、小试牛刀

以下是一个简单的 Python 脚本,功能是读取指定文件夹下的所有文本文件,查找特定 IP 并进行替换。

import os

def replace_ip_in_files(folder_path, old_ip, new_ip):
    # 遍历文件夹
    for filename in os.listdir(folder_path):
        # 扩展的文件类型
        if filename.endswith((".txt", ".log", ".ini")):  # 处理文本文件、日志文件和配置文件
            file_path = os.path.join(folder_path, filename)
            with open(file_path, 'r', encoding='utf-8') as file:
                content = file.read()

            # 替换 IP
            new_content = content.replace(old_ip, new_ip)

            # 写回文件
            with open(file_path, 'w', encoding='utf-8') as file:
                file.write(new_content)

if __name__ == "__main__":
    # 输入文件夹路径和要替换的 IP
    folder_path = input("请输入文件夹路径: ")
    old_ip = input("请输入要替换的旧IP: ")
    new_ip = input("请输入新的IP: ")

    # 调用函数
    replace_ip_in_files(folder_path, old_ip, new_ip)
    print("IP 替换完毕!")

说明

  • if filename.endswith(...) 语句中,使用了一个元组包含了多个文件扩展名。这样,无论是 .txt.log 还是 .ini 文件,都会被该条件满足并进行处理。
  • 你可以根据需要进一步扩展或修改文件类型,只需在元组中添加或删除相应的扩展名即可。

3、打包成 Windows 可执行exe程序

3.1、完善代码

在整个测试及完善体验中,加入了图形界面,解决编码、空行问题,报错提示,处理过的文件明细等。完整代码如下:

import os
import chardet
import tkinter as tk
from tkinter import filedialog, messagebox, Scrollbar, Text

def read_file_with_auto_encoding(file_path):
    with open(file_path, 'rb') as file:
        raw_data = file.read()
        result = chardet.detect(raw_data)
        encoding = result['encoding']

        # 如果 encoding 是 None,则使用默认编码
        if encoding is None:
            print(f"无法检测到编码,使用默认编码 'utf-8' 读取文件: {file_path}")
            encoding = 'utf-8'  # 使用默认编码

        return raw_data.decode(encoding)  # 使用检测到的编码解码

def remove_extra_newlines(content):
    """去除多余的换行符"""
    lines = content.splitlines()
    cleaned_lines = [line.strip() for line in lines if line.strip()]  # 过滤掉空行
    return '\n'.join(cleaned_lines)

def replace_ip_in_files(folder_path, old_ip, new_ip):
    processed_files = []  # 用于记录处理过的文件
    try:
        all_files = []

        # 获取所有待处理文件
        for root, dirs, files in os.walk(folder_path):
            for filename in files:
                if filename.endswith((".txt", ".conf", ".properties", ".ini", ".yml", ".json", ".xml")):
                    file_path = os.path.join(root, filename)
                    all_files.append(file_path)

        # 处理每个文件并显示进度
        total_files = len(all_files)
        for index, file_path in enumerate(all_files):
            status_text.set(f"正在处理文件: {file_path} ({index + 1}/{total_files})")

            # 使用自动编码读取文件
            content = read_file_with_auto_encoding(file_path)

            # 去除多余的换行符
            clean_content = remove_extra_newlines(content)

            # 替换 IP
            new_content = clean_content.replace(old_ip, new_ip)

            # 只有在确实有替换时才写入文件和记录文件
            if clean_content != new_content:
                with open(file_path, 'w', encoding='utf-8') as file:
                    file.write(new_content)
                processed_files.append(file_path)  # 记录处理过的文件

        if processed_files:
            show_processed_files(processed_files)
        else:
            messagebox.showinfo("信息", "没有找到需替换的内容。")

        status_text.set("替换完成!")

    except Exception as e:
        messagebox.showerror("错误", f"处理文件时出错: {e}")
        status_text.set("处理错误!请查看错误信息。")

def show_processed_files(processed_files):
    """显示处理过的文件列表,带滚动条"""
    # 创建新的窗口
    new_window = tk.Toplevel(root)
    new_window.title("处理过的文件列表")

    # 创建Text框和滚动条
    text_box = Text(new_window, width=80, height=20)
    scroll_bar = Scrollbar(new_window, command=text_box.yview)
    text_box.configure(yscrollcommand=scroll_bar.set)

    # 插入处理过的文件信息
    processed_files_message = "\n".join(processed_files)
    text_box.insert(tk.END, processed_files_message)

    # 布局组件
    text_box.pack(side=tk.LEFT, fill=tk.BOTH)
    scroll_bar.pack(side=tk.RIGHT, fill=tk.Y)

    # 禁止编辑
    text_box.config(state=tk.DISABLED)

def select_folder():
    folder_path = filedialog.askdirectory()
    folder_entry.delete(0, tk.END)  # 清空输入框
    folder_entry.insert(0, folder_path)  # 插入选中的文件夹路径

def start_replacement():
    folder_path = folder_entry.get()
    old_ip = old_ip_entry.get()
    new_ip = new_ip_entry.get()

    if not folder_path or not old_ip or not new_ip:
        messagebox.showwarning("警告", "请完整填写所有字段!")
        return

    replace_ip_in_files(folder_path, old_ip, new_ip)

# 创建主窗口
root = tk.Tk()
root.title("IP替换工具")

# 创建并放置组件
tk.Label(root, text="选择文件夹:").grid(row=0, column=0, padx=10, pady=10)
folder_entry = tk.Entry(root, width=50)
folder_entry.grid(row=0, column=1, padx=10, pady=10)
folder_button = tk.Button(root, text="浏览", command=select_folder)
folder_button.grid(row=0, column=2, padx=10, pady=10)

tk.Label(root, text="旧IP:").grid(row=1, column=0, padx=10, pady=10)
old_ip_entry = tk.Entry(root, width=50)
old_ip_entry.grid(row=1, column=1, padx=10, pady=10)

tk.Label(root, text="新IP:").grid(row=2, column=0, padx=10, pady=10)
new_ip_entry = tk.Entry(root, width=50)
new_ip_entry.grid(row=2, column=1, padx=10, pady=10)

# 状态框显示文件替换进度
status_text = tk.StringVar()
status_label = tk.Label(root, textvariable=status_text, fg="blue")
status_label.grid(row=3, column=0, columnspan=3, padx=10, pady=10)

replace_button = tk.Button(root, text="开始替换", command=start_replacement)
replace_button.grid(row=4, column=1, padx=10, pady=20)

# 启动主循环
root.mainloop()

3.2、打包成exe程序

假设你的 Python 脚本文件名为 EditIP.py,你可以在命令行(CMD 或 PowerShell)中导航到该文件所在的目录,并执行以下命令:

pyinstaller --onefile --windowed EditIP.py

参数说明:

  • onefile:生成一个单独的 .exe 文件,方便分发。
  • windowed:确保生成的程序在运行时不显示命令行窗口(适用于 GUI 程序)。

3.3、一睹芳容

手动添加了两个测试文件:

眼看一切都那么完美,是时候弄到项目上去试一试了。一试完美。

程序包可以在底部附件下载

4、调整Linux可运行脚本

转换为命令行脚本(CLI),移除所有tkinter的依赖,并通过命令行接受参数。以下是改编后的代码,它将通过命令行读取文件夹路径、旧IP和新IP,并进行替换。

修改后的代码

import os
import chardet
import sys

def read_file_with_auto_encoding(file_path):
    with open(file_path, 'rb') as file:
        raw_data = file.read()
        result = chardet.detect(raw_data)
        encoding = result['encoding']

        # 如果 encoding 是 None,则使用默认编码
        if encoding is None:
            print(f"无法检测到编码,使用默认编码 'utf-8' 读取文件: {file_path}")
            encoding = 'utf-8'  # 使用默认编码

        return raw_data.decode(encoding)  # 使用检测到的编码解码

def remove_extra_newlines(content):
    """去除多余的换行符"""
    lines = content.splitlines()
    cleaned_lines = [line.strip() for line in lines if line.strip()]  # 过滤掉空行
    return '\n'.join(cleaned_lines)

def replace_ip_in_files(folder_path, old_ip, new_ip):
    processed_files = []  # 用于记录处理过的文件
    try:
        all_files = []

        # 获取所有待处理文件
        for root, dirs, files in os.walk(folder_path):
            for filename in files:
                if filename.endswith((".txt", ".conf", ".properties", ".ini", ".yml", ".json", ".xml")):
                    file_path = os.path.join(root, filename)
                    all_files.append(file_path)

        # 处理每个文件并显示进度
        total_files = len(all_files)
        for index, file_path in enumerate(all_files):
            print(f"正在处理文件: {file_path} ({index + 1}/{total_files})")

            # 使用自动编码读取文件
            content = read_file_with_auto_encoding(file_path)

            # 去除多余的换行符
            clean_content = remove_extra_newlines(content)

            # 替换 IP
            new_content = clean_content.replace(old_ip, new_ip)

            # 只有在确实有替换时才写入文件和记录文件
            if clean_content != new_content:
                with open(file_path, 'w', encoding='utf-8') as file:
                    file.write(new_content)
                processed_files.append(file_path)  # 记录处理过的文件

        if processed_files:
            print("处理完毕,以下文件已被修改:")
            for processed_file in processed_files:
                print(processed_file)
        else:
            print("没有找到需替换的内容。")

        print("替换完成!")

    except Exception as e:
        print(f"处理文件时出错: {e}")

def main():
    if len(sys.argv) != 4:
        print("使用方法: python EditIP.py <文件夹路径> <旧IP> <新IP>")
        return

    folder_path = sys.argv[1]
    old_ip = sys.argv[2]
    new_ip = sys.argv[3]

    replace_ip_in_files(folder_path, old_ip, new_ip)

if __name__ == "__main__":
    main()

代码说明

  1. 命令行参数:使用sys.argv接受命令行输入。程序要求传入三个参数:文件夹路径、旧的IP与新的IP。
  2. 打印替换进度:通过print函数显示当前正在处理的文件及替换状态。
  3. 处理完的文件列表:在处理完成后,将修改过的文件列表打印到控制台。
  4. 异常处理:在所有文件处理结束后,会捕获并打印任何错误信息。

使用方法

  1. 将上面的代码保存为 EditIP.py
  2. 在命令行中运行该脚本,语法如下: bash python EditIP.py <文件夹路径> <旧IP> <新IP>

例如:

python EditIP.py /path/to/folder 192.168.1.1 192.168.1.2

通过这种方式,您将可以在命令行环境中执行文件内容替换。

文章目录