excel2txt/excel_to_txt_converter.py
2025-10-12 10:47:45 +08:00

197 lines
7.9 KiB
Python

import pandas as pd
import os
import tkinter as tk
from tkinter import ttk, filedialog, messagebox
import json
class ExcelToTxtConverter:
def __init__(self, root):
self.root = root
self.root.title("Excel转TXT工具")
self.root.geometry("600x500")
# 变量
self.excel_path = tk.StringVar()
self.export_path = tk.StringVar()
self.title_field = tk.StringVar()
self.content_field = tk.StringVar()
self.df = None
self.columns = []
self.setup_ui()
def setup_ui(self):
# 主框架
main_frame = ttk.Frame(self.root, padding="10")
main_frame.grid(row=0, column=0, sticky=(tk.W, tk.E, tk.N, tk.S))
# Excel文件选择
ttk.Label(main_frame, text="Excel文件:").grid(row=0, column=0, sticky=tk.W, pady=5)
ttk.Entry(main_frame, textvariable=self.excel_path, width=50).grid(row=0, column=1, padx=5)
ttk.Button(main_frame, text="浏览", command=self.browse_excel).grid(row=0, column=2, padx=5)
# 加载字段按钮
ttk.Button(main_frame, text="加载字段", command=self.load_fields).grid(row=1, column=1, pady=10)
# 字段选择框架
fields_frame = ttk.LabelFrame(main_frame, text="字段绑定", padding="10")
fields_frame.grid(row=2, column=0, columnspan=3, sticky=(tk.W, tk.E), pady=10)
# 标题字段选择
ttk.Label(fields_frame, text="标题字段:").grid(row=0, column=0, sticky=tk.W, pady=5)
self.title_combo = ttk.Combobox(fields_frame, textvariable=self.title_field, width=30)
self.title_combo.grid(row=0, column=1, padx=5)
# 内容字段选择
ttk.Label(fields_frame, text="内容字段:").grid(row=1, column=0, sticky=tk.W, pady=5)
self.content_combo = ttk.Combobox(fields_frame, textvariable=self.content_field, width=30)
self.content_combo.grid(row=1, column=1, padx=5)
# 导出路径选择
ttk.Label(main_frame, text="导出文件夹:").grid(row=3, column=0, sticky=tk.W, pady=5)
ttk.Entry(main_frame, textvariable=self.export_path, width=50).grid(row=3, column=1, padx=5)
ttk.Button(main_frame, text="浏览", command=self.browse_export_folder).grid(row=3, column=2, padx=5)
# 转换按钮
ttk.Button(main_frame, text="开始转换", command=self.convert, style="Accent.TButton").grid(row=4, column=1, pady=20)
# 状态显示
self.status_label = ttk.Label(main_frame, text="准备就绪", foreground="blue")
self.status_label.grid(row=5, column=0, columnspan=3, pady=5)
# 进度条
self.progress = ttk.Progressbar(main_frame, mode='determinate', length=400)
self.progress.grid(row=6, column=0, columnspan=3, pady=5)
# 配置网格权重
self.root.columnconfigure(0, weight=1)
self.root.rowconfigure(0, weight=1)
main_frame.columnconfigure(1, weight=1)
def browse_excel(self):
filename = filedialog.askopenfilename(
title="选择Excel文件",
filetypes=[("Excel文件", "*.xlsx *.xls"), ("所有文件", "*.*")]
)
if filename:
self.excel_path.set(filename)
def browse_export_folder(self):
folder = filedialog.askdirectory(title="选择导出文件夹")
if folder:
self.export_path.set(folder)
def load_fields(self):
if not self.excel_path.get():
messagebox.showwarning("警告", "请先选择Excel文件")
return
try:
# 读取Excel文件
self.df = pd.read_excel(self.excel_path.get())
self.columns = list(self.df.columns)
# 更新下拉框
self.title_combo['values'] = self.columns
self.content_combo['values'] = self.columns
if self.columns:
self.title_combo.current(0)
if len(self.columns) > 1:
self.content_combo.current(1)
else:
self.content_combo.current(0)
self.status_label.config(text=f"已加载 {len(self.df)} 行数据,{len(self.columns)} 个字段", foreground="green")
except Exception as e:
messagebox.showerror("错误", f"加载Excel文件失败: {str(e)}")
self.status_label.config(text="加载失败", foreground="red")
def sanitize_filename(self, filename):
"""清理文件名,移除非法字符"""
invalid_chars = '<>:"/\\|?*'
for char in invalid_chars:
filename = filename.replace(char, '_')
return filename.strip()
def convert(self):
if not self.excel_path.get():
messagebox.showwarning("警告", "请先选择Excel文件")
return
if not self.export_path.get():
messagebox.showwarning("警告", "请先选择导出文件夹")
return
if not self.title_field.get() or not self.content_field.get():
messagebox.showwarning("警告", "请先选择标题和内容字段")
return
if self.df is None:
messagebox.showwarning("警告", "请先加载Excel文件")
return
try:
# 创建导出文件夹
os.makedirs(self.export_path.get(), exist_ok=True)
# 获取字段索引
title_col = self.title_field.get()
content_col = self.content_field.get()
# 重置进度条
self.progress['maximum'] = len(self.df)
self.progress['value'] = 0
success_count = 0
error_count = 0
# 遍历每一行数据
for index, row in self.df.iterrows():
try:
# 获取标题和内容
title = str(row[title_col]) if pd.notna(row[title_col]) else f"文件_{index + 1}"
content = str(row[content_col]) if pd.notna(row[content_col]) else ""
# 清理文件名
filename = self.sanitize_filename(title) + '.txt'
filepath = os.path.join(self.export_path.get(), filename)
# 如果文件已存在,添加序号
counter = 1
original_filepath = filepath
while os.path.exists(filepath):
name, ext = os.path.splitext(original_filepath)
filepath = f"{name}_{counter}{ext}"
counter += 1
# 写入文件
with open(filepath, 'w', encoding='utf-8') as f:
f.write(content)
success_count += 1
except Exception as e:
error_count += 1
print(f"处理第 {index + 1} 行时出错: {str(e)}")
# 更新进度
self.progress['value'] = index + 1
self.root.update()
# 显示结果
messagebox.showinfo("完成", f"转换完成!\n成功: {success_count} 个文件\n失败: {error_count} 个文件")
self.status_label.config(text=f"转换完成!成功: {success_count}, 失败: {error_count}", foreground="green")
except Exception as e:
messagebox.showerror("错误", f"转换过程中出错: {str(e)}")
self.status_label.config(text="转换失败", foreground="red")
def main():
root = tk.Tk()
app = ExcelToTxtConverter(root)
root.mainloop()
if __name__ == "__main__":
main()