简介
把多个文本合成一个文件
下载软件
使用python写的文本文件合并软件
文本合并软件,界面由三个容器组成,上方是文件列表显示窗口,中间是一行按钮,下方是操作提示窗口。文件列表显示窗口使用tk.Treeview控件,包括文件序号、文件路径和文件编码。操作提示窗口使用tk.Text控件。
这个软件的功能包括:
选择目录:扫描文件后缀,转小写等于txt的文件,并将它们添加到文件列表显示窗口。
移除:从文件列表中移除选中的文件。
上移:将选中的文件往上移一格。
下移:将选中的文件往下移一格。
合并文件:将文件列表中的文件按照从上往下的顺序合并。
清空列表:清空文件列表显示窗口内容,为下一个文件夹合并做准备。
在合并文件之前,需要先转换文件编码。具体过程如下:
使用二进制方式读取文件。
使用chardet.detect检测文件编码。
如果检测到的编码不是None或文件长度大于0,则将文件内容解码为unicode。
将unicode编码的文件内容转换为utf-8编码。
最后,将文件列表中的文件按照从上往下的顺序合并。
设计过程
=============================================================
文本合并软件
窗口布局 3个容器
上 文件列表显示窗口
中 按钮 排成一行
下 操作提示窗口
2个窗口
1.文件列表显示窗口 tk.Treeview ,有两个属性 1.序号 2.文件路径 3.文件编码,使用chardet.detect. (需要有拖文件夹到里面自动识别功能
2.操作提示窗口 tk.Text
按钮区
1.选择目录:扫描文件后缀,转小写等于txt的文件
2.移除
3.上移,把文件往上移
4.下移
5.合并文件
6.清空列表 ,清空文件列表显示窗口内容 ,为下一个文件夹合并做准备
合并文件过程
转换文件编码过程
先把文件用二进制读取,
if encoding != 'None' or length >= 0:
文件能容.decode(encoding, errors='ignore') # 解码文件内容
在转换为为utf-8,为啥要用二进制转呢,因为有些字符直接转报错
最后按照 列表从上往下合并
=============================================================
代码 TextMerger.py
一片代码就可以运行 ,代码by 模型自动生成
import tkinter as tk
import os
import chardet
from tkinter import messagebox
import subprocess
import tkinter.ttk as ttk
import tkinter.filedialog
import winreg
# 定义寻找注册表中路径的函数
def find_program(program):
try:
registry_key = winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, r"SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\\" + program + ".exe")
value, regtype = winreg.QueryValueEx(registry_key, "")
return value
except WindowsError:
return None
class TextMerger:
def __init__(self):
self.window = tk.Tk()
self.window.title("文本合并软件")
# 设置窗口大小
self.window.geometry("600x600")
# 获取屏幕尺寸
screen_width = self.window.winfo_screenwidth()
screen_height = self.window.winfo_screenheight()
# 获取窗口实际大小
window_width = self.window.winfo_width()
window_height = self.window.winfo_height()
# 计算窗口左上角位置
x = (screen_width - window_width) // 2
y = (screen_height - window_height) // 2
# 设置窗口左上角位置
self.window.geometry("+%d+%d" % (x, y))
self.file_list = []
self.selected_item = None
# 创建三个容器,分别用于显示文件列表、按钮和操作提示
self.file_list_container = tk.Frame(self.window)
self.button_container = tk.Frame(self.window)
self.operation_prompt_container = tk.Frame(self.window)
# 创建文件列表显示窗口
self.file_list_label = tk.Label(self.file_list_container, text="文件列表")
self.file_list_label.pack(side=tk.TOP, padx=10, pady=10)
self.file_list_tree = ttk.Treeview(self.file_list_container, columns=('序号', '文件路径', '文件编码'), show='headings',selectmode='extended')
self.file_list_tree.heading('序号', text='序号')
self.file_list_tree.heading('文件路径', text='文件路径')
self.file_list_tree.heading('文件编码', text='文件编码')
self.file_list_tree.column('序号',minwidth=0, width=50, anchor='center')
self.file_list_tree.column('文件路径', width=399, anchor='w')
self.file_list_tree.column('文件编码', width=100, anchor='center')
self.file_list_tree.config(selectmode="browse")
self.file_list_tree.bind("<<TreeviewSelect>>", self.on_item_selected)
# 绑定拖放事件
self.file_list_tree.bind("<<TreeviewDrop>>", self.on_drag_enter)
self.file_list_tree.bind("<<TreeviewEndDrag>>", self.on_drop)
# 绑定拖放进入和离开事件
self.file_list_tree.bind("<<TreeviewDragEnter>>", self.on_drag_enter)
self.file_list_tree.bind("<<TreeviewDragLeave>>", self.on_drag_leave)
self.file_list_tree.pack(side=tk.TOP, padx=10, pady=10)
# 创建按钮区
self.select_dir_button = tk.Button(self.button_container, text="选择目录", command=self.select_directory)
self.select_dir_button.pack(side=tk.LEFT, padx=10, pady=10)
self.remove_button = tk.Button(self.button_container, text="移除", command=self.remove_selected_file)
self.remove_button.pack(side=tk.LEFT, padx=10, pady=10)
self.up_button = tk.Button(self.button_container, text="上移", command=self.move_file_up)
self.up_button.pack(side=tk.LEFT, padx=10, pady=10)
self.down_button = tk.Button(self.button_container, text="下移", command=self.move_file_down)
self.down_button.pack(side=tk.LEFT, padx=10, pady=10)
self.merge_button = tk.Button(self.button_container, text="合并文件", command=self.merge_files_confirm)
self.merge_button.pack(side=tk.LEFT, padx=10, pady=10)
self.clear_button = tk.Button(self.button_container, text="清空列表", command=self.clear_file_list)
self.clear_button.pack(side=tk.LEFT, padx=10, pady=10)
# 创建操作提示窗口
self.operation_prompt_label = tk.Label(self.operation_prompt_container, text="操作提示")
self.operation_prompt_label.pack(side=tk.TOP, padx=10, pady=10)
self.operation_prompt_text = tk.Text(self.operation_prompt_container, height=10, width=80)
self.operation_prompt_text.pack(side=tk.TOP, padx=10, pady=10)
# 将三个容器添加到窗口中
self.file_list_container.pack(side=tk.TOP, padx=10, pady=10)
self.button_container.pack(side=tk.TOP, padx=10, pady=10)
self.operation_prompt_container.pack(side=tk.TOP, padx=10, pady=10)
self.window.mainloop()
def select_directory(self):
# 打开文件选择对话框,选择一个文件夹
directory = tk.filedialog.askdirectory()
if directory:
# 遍历文件夹下的所有txt文件,并将它们添加到文件列表中
for root, dirs, files in os.walk(directory):
for file in files:
if file.lower().endswith('.txt'):
file_path = os.path.join(root, file)
# 获取文件编码
with open(file_path, 'rb') as f:
encoding = chardet.detect(f.read(10000))['encoding']
# 将文件信息添加到文件列表中
self.file_list.append({'path': file_path, 'encoding': encoding})
self.file_list_tree.insert('', 'end', values=(len(self.file_list), file_path, encoding))
def remove_selected_file(self):
# 删除选中的文件
self.operation_prompt_text.insert('end', "移除列表序号:"+ str(self.selected_item+1) +"\n")
self.file_list.pop(self.selected_item)
self.selected_item = None
self.refresh_file_list()
def move_file_up(self):
# 将选中的文件往上移一位
if self.selected_item > 0:
self.file_list[self.selected_item], self.file_list[self.selected_item - 1] = self.file_list[self.selected_item - 1], self.file_list[self.selected_item]
self.selected_item -= 1
self.refresh_file_list()
def move_file_down(self):
# 将选中的文件往下移一位
if self.selected_item < len(self.file_list) - 1:
self.file_list[self.selected_item], self.file_list[self.selected_item + 1] = self.file_list[self.selected_item + 1], self.file_list[self.selected_item]
self.selected_item += 1
self.refresh_file_list()
def merge_files_confirm(self):
#文件合并
self.operation_prompt_text.insert('end', "开始合并文件 ...\n" )
merged_content =''
for file_info in self.file_list:
with open(file_info['path'], 'rb') as f:
content = f.read()
if len(content)>0 and file_info['encoding'] != 'None':
try:
self.operation_prompt_text.insert('end', "合并文件 %s\n" % file_info['path'])
content = content.decode(file_info['encoding'], errors='ignore') # 解码文件内容
if isinstance(content, bytes):
self.operation_prompt_text.insert('end', "文件无法用编码 %s 解码\n" % file_info['path'])
continue
# 转换为utf-8编码
content8 = content.encode("utf-8").decode("utf-8")
merged_content = merged_content +str(content8)
except:
self.operation_prompt_text.insert('end', "文件无法用编码 %s 解码\n" % file_info['path'])
continue
# 写入合并后的文件
file_name = 'merged.txt'
file_path = os.path.join(os.getcwd(), file_name)
with open(file_path, 'w', encoding='utf-8') as f:
f.write(merged_content)
# 提示合并完成
self.operation_prompt_text.insert('end', "文件合并完成,合并后的文件为 %s\n" % file_path)
self.operation_prompt_text.insert('end', "打开合并文件 %s\n" % file_path)
# 从注册表中获取 Notepad++ 的安装路径
notepad_plus_plus_path = find_program("notepad++")
if os.path.exists(notepad_plus_plus_path):
subprocess.Popen([notepad_plus_plus_path, file_path])
else:
subprocess.Popen(['notepad.exe', file_path])
os.startfile(os.getcwd()) # 打开系统文件夹并选中该文件夹
def clear_file_list(self):
# 清空文件列表
self.file_list = []
self.refresh_file_list()
self.operation_prompt_text.insert('end', "你清空文件列表.\n")
def refresh_file_list(self):
# 刷新文件列表
self.file_list_tree.delete(*self.file_list_tree.get_children())
for i, file_info in enumerate(self.file_list):
self.file_list_tree.insert('', 'end', values=(i + 1, file_info['path'], file_info['encoding']))
def on_item_selected(self, event):
selected_items = event.widget.selection()
for item in selected_items:
index = self.file_list_tree.index(item)
if index is not None:
self.selected_item = index
else:
self.selected_item = None
self.operation_prompt_text.insert('end', "选中:"+ str(self.selected_item+1) +"\n")
def on_drag_enter(self, event):
# 拖动文件夹到窗口时高亮窗口
self.window.config(background="#aaffaa")
def on_drag_leave(self, event):
# 拖动文件夹离开窗口时恢复窗口背景色
self.window.config(background="#ffffff")
def on_drop(self, event):
# 将拖入窗口的文件夹路径添加到文件列表中
file_path = event.data.strip()
if os.path.isdir(file_path):
for root, dirs, files in os.walk(file_path):
for file in files:
if file.lower().endswith('.txt'):
file_path = os.path.join(root, file)
# 获取文件编码
with open(file_path, 'rb') as f:
encoding = chardet.detect(f.read())['encoding']
# 将文件信息添加到文件列表中
self.file_list.append({'path': file_path, 'encoding': encoding})
self.refresh_file_list()
self.window.config(background="#ffffff")
else:
self.operation_prompt_text.insert('end', "拖入的不是文件夹\n")
def update_message(self, message):
self.operation_prompt_text.delete("1.0", "end")
self.operation_prompt_text.insert("end", message)
if __name__ == '__main__':
TextMerger()