197 lines
7.9 KiB
Python
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() |