当前位置: 首页 > news >正文

AI写程序:用 AI 实现一个递归批量转化 GBK/GB2312 转 UTF-8 工具:轻松解决文本编码转换难题

用 AI 实现一个递归批量转化 GBK/GB2312 转 UTF-8 工具

在处理历史文件或与不同系统交互时,我们经常会遇到 GBK 或 GB2312 编码的文本文件。虽然现在 UTF-8 是主流,但手动转换这些旧编码文件既繁琐又容易出错。为了解决这个问题,我开发了一个简单的图形界面工具,可以批量将指定文件夹下的 GBK/GB2312 文件转换为 UTF-8 编码。

工具概览

这个工具使用 Python 和 Tkinter 构建,提供了一个直观的用户界面。它具备以下主要功能:

  • 图形界面: 简洁易用,无需命令行操作。
  • 文件夹选择: 方便地选择包含需要转换文件的文件夹。
  • 智能编码检测: 利用 chardet 库自动识别文件编码,并针对 GBK/GB2312 做了优化处理。
  • 批量转换: 递归遍历文件夹,自动处理所有识别出的 GBK/GB2312 文本文件。
  • 跳过机制: 自动跳过已经是 UTF-8 或无法识别编码的文件。
  • 实时日志: 在界面上显示详细的转换过程和结果。
  • 多线程: 转换过程在后台线程进行,避免界面卡顿。

界面截图

请添加图片描述

如何使用

您可以选择以下两种方式之一来使用该工具:

1. 直接运行 (需要 Python 环境)

  • 确保您的电脑已安装 Python 3。
  • 下载或克隆项目代码。
  • 在项目目录下打开终端或命令提示符,安装依赖:
    pip install -r requirements.txt
    
  • 运行主程序:
    python main.py
    
  • 在弹出的窗口中,点击“浏览”选择目标文件夹,然后点击“开始转换”。

2. 使用预编译的可执行文件

  • 访问项目的 GitHub Releases 页面。
  • 下载适用于您操作系统的最新版本(例如 Windows 下载 .exe 文件)。
  • 直接双击运行下载的文件即可。

完整源代码

以下是工具的主要 Python 源代码 (main.py):

import tkinter as tk
from tkinter import filedialog, messagebox, scrolledtext
import os
import chardet
import threading
import webbrowser # <-- 添加导入# 支持检测和转换的编码列表
SUPPORTED_ENCODINGS = ['gb2312', 'gbk']
# 目标编码
TARGET_ENCODING = 'utf-8'
# 常见的文本和代码文件扩展名 (小写)
TEXT_FILE_EXTENSIONS = {'.txt', '.log', '.csv', '.json', '.xml', '.html', '.htm', '.css', '.js', '.py', '.java', '.c', '.cpp', '.h', '.hpp', '.cs', '.php', '.rb', '.go', '.rs', '.swift', '.kt', '.kts', '.sql', '.md', '.rst', '.yaml', '.yml', '.ini', '.cfg', '.toml', '.sh', '.bat', '.ps1'
}class EncodingConverterApp:def __init__(self, master):self.master = mastermaster.title("GBK/GB2312 转 UTF-8 工具")master.geometry("600x480") # <-- 调整窗口大小以容纳链接# 文件夹选择self.folder_path_var = tk.StringVar()tk.Label(master, text="选择文件夹:").grid(row=0, column=0, padx=5, pady=5, sticky='w')self.folder_entry = tk.Entry(master, textvariable=self.folder_path_var, width=50)self.folder_entry.grid(row=0, column=1, padx=5, pady=5, sticky='ew')self.browse_button = tk.Button(master, text="浏览", command=self.browse_folder)self.browse_button.grid(row=0, column=2, padx=5, pady=5)# 开始转换按钮self.convert_button = tk.Button(master, text="开始转换", command=self.start_conversion_thread)self.convert_button.grid(row=1, column=0, columnspan=3, pady=10)# 日志输出区域tk.Label(master, text="转换日志:").grid(row=2, column=0, padx=5, pady=5, sticky='w')self.log_text = scrolledtext.ScrolledText(master, wrap=tk.WORD, height=15)self.log_text.grid(row=3, column=0, columnspan=3, padx=5, pady=5, sticky='nsew')self.log_text.config(state=tk.DISABLED) # 初始设为不可编辑# GitHub 链接self.github_url = "https://github.com/dependon/gbk2utf8"self.github_label = tk.Label(master, text="项目地址: " + self.github_url, fg="blue", cursor="hand2")self.github_label.grid(row=4, column=0, columnspan=3, padx=5, pady=(5, 10), sticky='w') # 放置在日志下方self.github_label.bind("<Button-1>", self.open_link)# 配置行列权重,使控件随窗口缩放master.grid_rowconfigure(3, weight=1) # 日志区域占满剩余空间master.grid_rowconfigure(4, weight=0) # 链接行不扩展master.grid_columnconfigure(1, weight=1)def log(self, message):"""向日志区域添加消息"""self.log_text.config(state=tk.NORMAL)self.log_text.insert(tk.END, message + "\n")self.log_text.see(tk.END) # 滚动到底部self.log_text.config(state=tk.DISABLED)self.master.update_idletasks() # 强制更新界面def browse_folder(self):"""打开文件夹选择对话框"""folder_selected = filedialog.askdirectory()if folder_selected:self.folder_path_var.set(folder_selected)self.log(f"已选择文件夹: {folder_selected}")def is_text_file(self, filename):"""根据扩展名判断是否可能是文本或代码文件"""_, ext = os.path.splitext(filename)return ext.lower() in TEXT_FILE_EXTENSIONSdef detect_encoding(self, file_path):"""检测文件编码"""try:with open(file_path, 'rb') as f:raw_data = f.read(4096) # 读取一部分数据进行检测result = chardet.detect(raw_data)encoding = result['encoding']confidence = result['confidence']# chardet有时会将GBK/GB2312检测为其他编码,增加一些兼容性判断if encoding and encoding.lower() in ['gb2312', 'gbk', 'gb18030']:return encoding.lower(), confidence# 对于置信度不高的常见误判,也尝试按GBK处理if encoding and confidence < 0.9 and encoding.lower() in ['ascii', 'windows-1252']:# 尝试用GBK解码,如果成功则认为是GBKtry:raw_data.decode('gbk')return 'gbk', 0.5 # 置信度设低一些except UnicodeDecodeError:passreturn encoding, confidenceexcept Exception as e:self.log(f"检测编码错误 ({os.path.basename(file_path)}): {e}")return None, 0def convert_file_encoding(self, file_path, original_encoding):"""将文件从原始编码转换为UTF-8"""try:with open(file_path, 'r', encoding=original_encoding, errors='replace') as f_read:content = f_read.read()# 检查是否真的需要转换 (避免不必要的写操作和潜在BOM问题)needs_conversion = Falsetry:# 尝试用UTF-8无BOM读取,如果失败或内容不同,则需要转换with open(file_path, 'r', encoding='utf-8') as f_utf8_check:utf8_content = f_utf8_check.read()if content != utf8_content:needs_conversion = Trueexcept UnicodeDecodeError:needs_conversion = Trueexcept Exception:# 其他读取错误,也认为需要转换以修复needs_conversion = Trueif needs_conversion:with open(file_path, 'w', encoding=TARGET_ENCODING) as f_write:f_write.write(content)self.log(f"成功: {os.path.basename(file_path)} ({original_encoding} -> {TARGET_ENCODING})")return Trueelse:self.log(f"跳过: {os.path.basename(file_path)} (已经是 {TARGET_ENCODING} 或无需转换)")return Falseexcept Exception as e:self.log(f"转换失败: {os.path.basename(file_path)} - {e}")return Falsedef process_folder(self, folder_path):"""处理指定文件夹下的所有文件"""converted_count = 0skipped_count = 0error_count = 0processed_files = 0self.log(f"\n开始扫描文件夹: {folder_path}")for root, _, files in os.walk(folder_path):for filename in files:if not self.is_text_file(filename):# self.log(f"忽略非文本文件: {filename}")continuefile_path = os.path.join(root, filename)processed_files += 1self.log(f"正在处理: {file_path}")encoding, confidence = self.detect_encoding(file_path)if encoding and encoding.lower() in SUPPORTED_ENCODINGS:self.log(f"检测到 {encoding.upper()} (置信度: {confidence:.2f}): {filename}")if self.convert_file_encoding(file_path, encoding):converted_count += 1else:error_count += 1elif encoding:# self.log(f"跳过 (非GBK/GB2312编码: {encoding}): {filename}")skipped_count += 1else:# self.log(f"跳过 (无法检测编码): {filename}")skipped_count += 1error_count += 1 # 无法检测也算一种错误self.log(f"\n处理完成。共扫描 {processed_files} 个文本/代码文件。")self.log(f"成功转换: {converted_count}")self.log(f"跳过文件: {skipped_count}")self.log(f"转换/检测失败: {error_count}")messagebox.showinfo("完成", f"转换完成!\n成功: {converted_count}\n跳过: {skipped_count}\n失败: {error_count}")# 转换完成后重新启用按钮self.convert_button.config(state=tk.NORMAL)self.browse_button.config(state=tk.NORMAL)def start_conversion_thread(self):"""在单独的线程中开始转换过程,避免GUI卡死"""folder_path = self.folder_path_var.get()if not folder_path or not os.path.isdir(folder_path):messagebox.showerror("错误", "请先选择一个有效的文件夹!")return# 禁用按钮,防止重复点击self.convert_button.config(state=tk.DISABLED)self.browse_button.config(state=tk.DISABLED)self.log_text.config(state=tk.NORMAL)self.log_text.delete('1.0', tk.END) # 清空日志self.log_text.config(state=tk.DISABLED)# 创建并启动线程conversion_thread = threading.Thread(target=self.process_folder, args=(folder_path,), daemon=True)conversion_thread.start()def open_link(self, event):"""打开GitHub链接"""webbrowser.open_new(self.github_url)if __name__ == "__main__":root = tk.Tk()app = EncodingConverterApp(root)root.mainloop()

项目地址

如果您对这个工具感兴趣,或者想查看完整的项目代码和构建说明,请访问项目的 GitHub 仓库:

https://github.com/dependon/gbk2utf8

希望这个小工具能对您有所帮助!

相关文章:

  • Vue与React组件化设计对比
  • Rust + WebAssembly 生产部署指南
  • apollo 动态配置
  • Kubernetes》》K8S》》Pod的健康检查
  • 绿幕抠图直播软件-蓝松抠图插件--使用相机直播,灯光需要怎么打?
  • 多路由器通过三层交换机互相通讯(单臂路由+静态路由+默认路由版),通过三层交换机让pc端相互通讯
  • 如何分析服务器日志以追踪黑客攻击行为
  • 阿里云RAM账号免密登录Java最佳实践
  • DP 32bit位宽数据扰码实现和仿真
  • springboot整合阿里云百炼DeepSeek,实现sse流式打印
  • Modbus TCP转Profibus DP主站网关:跨协议集成的核心枢纽
  • HTTP/1.1 对头堵塞问题
  • JMeter中设置HTTPS请求
  • MySQL游标(cursor)详解
  • 3 提示词工程指南-提示词编辑 - 持续更新
  • LWIP_MQTT连接ONENET
  • Java 中常用队列用法详解
  • OpenGL shader开发实战学习笔记:第十一章 立方体贴图和天空盒
  • 计算机网络基础概论
  • Linux中docker容器拉取镜像失败解决方案
  • 深圳拟出让3宗居住用地,共计用地面积6.77公顷
  • 紫光集团原董事长赵伟国一审被判死缓
  • 夜读丨取稿费的乐趣
  • 习近平结束对俄罗斯国事访问并出席纪念苏联伟大卫国战争胜利80周年庆典回到北京
  • 湖南省职业病防治院通报3岁女童确诊“铊中毒”:去年病例,编辑误写为“近日”
  • 上海将发布新一版不予行政处罚清单、首份减轻行政处罚清单