基于Python實(shí)現(xiàn)excel拆分和合并工具并打包
拆分代碼
處理核心流程
- 驗(yàn)證輸入
- 讀取數(shù)據(jù)
- 拆分?jǐn)?shù)據(jù)
- 保存文件

拆分代碼的核心邏輯可以總結(jié)為:“讀取數(shù)據(jù)→計(jì)算拆分規(guī)則→按規(guī)則切割數(shù)據(jù)→保存小文件”,具體步驟如下,結(jié)合代碼細(xì)節(jié)一步步解釋:
前提:用戶輸入準(zhǔn)備
在拆分前,程序需要兩個(gè)關(guān)鍵信息:
- 要拆分的Excel文件路徑(用戶通過“瀏覽”按鈕選擇)
- 每個(gè)小文件包含的行數(shù)(用戶在輸入框填寫,默認(rèn)10000行)
這兩個(gè)信息會(huì)通過start_split函數(shù)做有效性檢查:
- 檢查文件是否存在(如果沒選文件或文件路徑無效,彈出警告)
- 檢查行數(shù)是否為正數(shù)(如果填0或負(fù)數(shù)或文字,彈出警告)
核心拆分函數(shù)split_excel的邏輯(重點(diǎn))
當(dāng)輸入有效后,程序調(diào)用split_excel(file_path, rows_per_file)函數(shù),這個(gè)函數(shù)是拆分的核心,步驟如下:
步驟1:讀取Excel數(shù)據(jù)
用pandas庫的pd.read_excel(file_path)讀取整個(gè)Excel文件,得到一個(gè)“數(shù)據(jù)框”df(可以理解為內(nèi)存中的表格,包含所有行和列)。
然后用len(df)獲取總數(shù)據(jù)行數(shù)(比如總共有25000行)。
步驟2:檢查數(shù)據(jù)是否為空
如果總行數(shù)為0(即Excel里沒數(shù)據(jù)),直接彈出“錯(cuò)誤”提示,終止拆分。
步驟3:計(jì)算需要拆分成多少個(gè)文件
用“總行數(shù) ÷ 每個(gè)文件的行數(shù)”,并向上取整(避免最后一個(gè)文件行數(shù)不足時(shí)被漏掉)。
例如:總共有25000行,每個(gè)文件10000行 → 25000 ÷ 10000 = 2.5 → 向上取整后是3個(gè)文件。
代碼里用math.ceil(total_rows / rows_per_file)實(shí)現(xiàn)這個(gè)計(jì)算。
步驟4:確定拆分后文件的保存位置和名稱
- 保存位置:和原文件在同一個(gè)文件夾(用
os.path.dirname(file_path)獲取原文件目錄)。 - 文件名稱:原文件名 + “_拆分_序號(hào)”(比如原文件叫
data.xlsx,拆分后是data_拆分_1.xlsx、data_拆分_2.xlsx…)。
步驟5:循環(huán)拆分并保存每個(gè)小文件
用for循環(huán)遍歷每個(gè)要生成的小文件(從0到“文件數(shù)量-1”),每次循環(huán)做3件事:
計(jì)算當(dāng)前小文件的“起始行”和“結(jié)束行”:
- 起始行 = 序號(hào) × 每個(gè)文件的行數(shù)(比如第1個(gè)文件是0×10000=0,第2個(gè)是1×10000=10000)
- 結(jié)束行 = (序號(hào)+1)× 每個(gè)文件的行數(shù),但如果超過總行數(shù),就取總行數(shù)(避免越界)。例如總25000行,第3個(gè)文件的結(jié)束行是
min(3×10000, 25000) = 25000。
提取當(dāng)前小文件的數(shù)據(jù):用df.iloc[start_row:end_row]從總數(shù)據(jù)中“切出”當(dāng)前范圍的行(比如第3個(gè)文件取20000到25000行),得到子數(shù)據(jù)框df_subset。
保存子文件:用df_subset.to_excel(output_path, index=False)將子數(shù)據(jù)框保存為Excel文件(index=False表示不保存行號(hào),避免多余數(shù)據(jù))。
步驟6:反饋結(jié)果
- 如果所有文件都保存成功,彈出“成功”提示,顯示拆分的文件數(shù)量(比如“共拆分成3個(gè)文件”)。
- 如果過程中出錯(cuò)(比如文件損壞、沒有權(quán)限保存等),彈出“錯(cuò)誤”提示,顯示具體錯(cuò)誤原因。
完整代碼
“先讀全表,算好要拆成幾個(gè)文件,再按行數(shù)一段一段切下來,每段存成一個(gè)新Excel,最后告訴用戶結(jié)果”。
整個(gè)過程不需要手動(dòng)計(jì)算,程序會(huì)自動(dòng)處理邊界情況(比如最后一個(gè)文件行數(shù)不足),并通過圖形界面讓操作更簡單。
import pandas as pd
import os
import tkinter as tk
from tkinter import filedialog, messagebox
from tkinter import ttk
import math
def split_excel(file_path, rows_per_file):
"""將Excel文件按指定行數(shù)拆分成多個(gè)文件"""
try:
# 讀取Excel文件
df = pd.read_excel(file_path)
total_rows = len(df)
if total_rows == 0:
messagebox.showerror("錯(cuò)誤", "Excel文件中沒有數(shù)據(jù)!")
return
# 計(jì)算需要拆分的文件數(shù)量
num_files = math.ceil(total_rows / rows_per_file)
# 獲取文件目錄和文件名(不含擴(kuò)展名)
file_dir = os.path.dirname(file_path)
file_name = os.path.splitext(os.path.basename(file_path))[0]
# 拆分文件
for i in range(num_files):
start_row = i * rows_per_file
end_row = min((i + 1) * rows_per_file, total_rows)
# 提取數(shù)據(jù)子集
df_subset = df.iloc[start_row:end_row]
# 生成輸出文件名
output_filename = f"{file_name}_拆分_{i+1}.xlsx"
output_path = os.path.join(file_dir, output_filename)
# 保存拆分后的文件
df_subset.to_excel(output_path, index=False)
messagebox.showinfo("成功", f"文件拆分完成!\n共拆分成 {num_files} 個(gè)文件\n每個(gè)文件約 {rows_per_file} 行")
except Exception as e:
messagebox.showerror("錯(cuò)誤", f"拆分過程中出現(xiàn)錯(cuò)誤:{str(e)}")
def select_file():
"""選擇Excel文件"""
file_path = filedialog.askopenfilename(
title="選擇要拆分的Excel文件",
filetypes=[("Excel files", "*.xlsx *.xls"), ("All files", "*.*")]
)
if file_path:
file_var.set(file_path)
# 自動(dòng)讀取文件信息
try:
df = pd.read_excel(file_path)
total_rows = len(df)
info_var.set(f"文件總行數(shù): {total_rows} 行")
except Exception as e:
info_var.set("無法讀取文件信息")
def start_split():
"""開始拆分"""
file_path = file_var.get()
if not file_path or not os.path.exists(file_path):
messagebox.showwarning("警告", "請(qǐng)先選擇有效的Excel文件!")
return
try:
rows_per_file = int(rows_var.get())
if rows_per_file <= 0:
messagebox.showwarning("警告", "請(qǐng)輸入有效的行數(shù)(大于0)!")
return
except ValueError:
messagebox.showwarning("警告", "請(qǐng)輸入有效的數(shù)字!")
return
split_excel(file_path, rows_per_file)
# 創(chuàng)建主窗口
root = tk.Tk()
root.title("Excel文件拆分工具:數(shù)據(jù)分析")
root.geometry("550x200")
# 變量
file_var = tk.StringVar()
rows_var = tk.StringVar(value="10000") # 默認(rèn)10000行
info_var = tk.StringVar(value="請(qǐng)選擇Excel文件")
# 界面布局
frame = ttk.Frame(root, padding="15")
frame.grid(row=0, column=0, sticky=(tk.W, tk.E, tk.N, tk.S))
# 文件選擇行
ttk.Label(frame, text="選擇Excel文件:").grid(row=0, column=0, sticky=tk.W, pady=5)
ttk.Entry(frame, textvariable=file_var, width=40).grid(row=0, column=1, padx=5, pady=5)
ttk.Button(frame, text="瀏覽", command=select_file).grid(row=0, column=2, padx=5, pady=5)
# 文件信息顯示
ttk.Label(frame, textvariable=info_var, foreground="blue").grid(row=1, column=1, sticky=tk.W, pady=2)
# 行數(shù)設(shè)置行
ttk.Label(frame, text="每份文件行數(shù):").grid(row=2, column=0, sticky=tk.W, pady=10)
ttk.Entry(frame, textvariable=rows_var, width=15).grid(row=2, column=1, sticky=tk.W, padx=5, pady=10)
ttk.Label(frame, text="行").grid(row=2, column=1, sticky=tk.W, padx=100, pady=10)
# 開始拆分按鈕
ttk.Button(frame, text="開始拆分", command=start_split).grid(row=3, column=1, pady=20)
# 配置網(wǎng)格權(quán)重
root.columnconfigure(0, weight=1)
root.rowconfigure(0, weight=1)
frame.columnconfigure(1, weight=1)
root.mainloop()
合并代碼
合并代碼的核心邏輯可以總結(jié)為:“選一個(gè)基準(zhǔn)文件→自動(dòng)找相似文件→確認(rèn)后合并→統(tǒng)一格式并保存”,整個(gè)過程不需要手動(dòng)逐個(gè)選擇文件,重點(diǎn)在“智能識(shí)別相似文件”和“兼容不同格式的表格”。下面分步驟拆解邏輯:
前提:用戶輸入準(zhǔn)備
程序需要用戶先做一件事:選擇一個(gè)“基準(zhǔn)Excel文件”(通過“瀏覽”按鈕選擇)。這個(gè)文件的作用是“模板”——程序會(huì)以它的文件名為線索,去同目錄下找其他“長得像”的文件。
核心合并函數(shù)combine_similar_files的邏輯(重點(diǎn))
當(dāng)用戶點(diǎn)擊“開始智能合并”后,程序調(diào)用這個(gè)函數(shù),核心步驟如下:
步驟1:定位文件目錄并收集所有Excel文件
- 先確定基準(zhǔn)文件所在的文件夾(比如基準(zhǔn)文件在
D:\數(shù)據(jù),就只在這個(gè)文件夾里找其他文件)。 - 遍歷這個(gè)文件夾,把所有以
.xlsx或.xls結(jié)尾的文件都挑出來(這些是潛在的合并對(duì)象)。 - 如果文件夾里沒有Excel文件,直接彈“錯(cuò)誤”提示(比如“目錄中沒有找到Excel文件”)。
步驟2:從基準(zhǔn)文件名中提取“相似模式”(核心?。?/h4>
這是程序“智能”的關(guān)鍵——通過基準(zhǔn)文件名,提煉出一個(gè)“共同特征”,用來判斷其他文件是否相似。比如:
- 若基準(zhǔn)文件是
銷售數(shù)據(jù)_1.xlsx,會(huì)提煉出銷售數(shù)據(jù)(去掉數(shù)字和后綴); - 若基準(zhǔn)文件是
報(bào)表-202401.xlsx,會(huì)提煉出報(bào)表-2024(去掉末尾的日期序號(hào)); - 若基準(zhǔn)文件是
客戶列表 v2.xlsx,會(huì)提煉出客戶列表(去掉版本號(hào))。
具體由extract_common_pattern函數(shù)實(shí)現(xiàn),邏輯是:
- 先去掉文件后綴(如
.xlsx),只看文件名主體; - 去掉文件名里的數(shù)字(比如
文件123→文件); - 按常見分隔符(
_、-、空格)拆分,取前面的部分(比如數(shù)據(jù)_拆分_3→數(shù)據(jù)_拆分); - 如果以上都不適用,就用整個(gè)文件名主體作為模式。
步驟3:用“相似模式”篩選同目錄的文件
有了“相似模式”后,程序會(huì)在步驟1收集的所有Excel文件中,篩選出符合模式的文件。由find_similar_files函數(shù)實(shí)現(xiàn),比如:
- 模式是
銷售數(shù)據(jù),則銷售數(shù)據(jù)_2.xlsx、銷售數(shù)據(jù)_3.xlsx會(huì)被選中(包含銷售數(shù)據(jù)); - 模式是
報(bào)表-2024,則報(bào)表-202402.xlsx、報(bào)表-202403.xlsx會(huì)被選中(以模式開頭)。
篩選時(shí)會(huì)自動(dòng)排除基準(zhǔn)文件本身嗎?不,會(huì)包含基準(zhǔn)文件(最終合并的文件列表里,基準(zhǔn)文件是第一個(gè))。
步驟4:讓用戶確認(rèn)要合并的文件
如果篩選出的相似文件只有1個(gè)(也就是只有基準(zhǔn)文件自己),會(huì)彈“提示”說“沒有找到其他相似文件”,終止流程。
如果有多個(gè),會(huì)列出所有文件(比如“銷售數(shù)據(jù)_1.xlsx、銷售數(shù)據(jù)_2.xlsx、銷售數(shù)據(jù)_3.xlsx”),讓用戶選“是”或“否”——用戶確認(rèn)后才繼續(xù)合并。
步驟5:合并文件數(shù)據(jù)(處理格式兼容)
這一步是實(shí)際合并數(shù)據(jù),核心是解決“不同文件列不一致”的問題(比如A文件有“姓名、金額”,B文件只有“姓名”)。步驟:
- 逐個(gè)讀取相似文件的表格數(shù)據(jù)(用
pd.read_excel),得到每個(gè)文件的“數(shù)據(jù)框”(內(nèi)存中的表格)。 - 第一個(gè)文件的數(shù)據(jù)作為“基準(zhǔn)結(jié)構(gòu)”,后續(xù)文件的數(shù)據(jù)會(huì)和它對(duì)齊:
- 如果列名完全一致(比如都有“姓名、金額”),直接拼接(按行疊加);
- 如果列名不一致(比如B文件缺“金額”),則給B文件自動(dòng)補(bǔ)一個(gè)“金額”列,空值填充(保證合并后所有列名和第一個(gè)文件一致)。
- 用
pd.concat把所有數(shù)據(jù)框“拼”成一個(gè)大的數(shù)據(jù)框(df_combined)。
步驟6:保存合并結(jié)果(避免文件名沖突)
- 生成結(jié)果文件名:用步驟2提煉的“相似模式”+“_合并結(jié)果.xlsx”(比如
銷售數(shù)據(jù)_合并結(jié)果.xlsx)。 - 檢查是否有重名:如果同名文件已存在,自動(dòng)加序號(hào)(比如
銷售數(shù)據(jù)_合并結(jié)果(1).xlsx、(2).xlsx)。 - 保存到基準(zhǔn)文件所在的文件夾(用
to_excel函數(shù))。
步驟7:反饋合并結(jié)果
- 成功:彈窗顯示“合并了3個(gè)文件,總行數(shù)1500,保存路徑XXX”;
- 失?。簭棿帮@示具體錯(cuò)誤(比如“某文件損壞無法讀取”“沒有權(quán)限保存”)。
完整代碼
“以一個(gè)文件為模板,自動(dòng)找到同目錄下名字相似的其他Excel文件,對(duì)齊它們的表格列,拼在一起后存成一個(gè)新文件,過程中讓用戶確認(rèn)并反饋結(jié)果”。
這個(gè)邏輯的核心優(yōu)勢是“智能找文件”(不用手動(dòng)選)和“自動(dòng)兼容格式”(不怕列不一致),特別適合處理按序號(hào)拆分的文件(如數(shù)據(jù)1、數(shù)據(jù)2)或按時(shí)間拆分的文件(如202401報(bào)表、202402報(bào)表)。
import pandas as pd
import os
import tkinter as tk
from tkinter import filedialog, messagebox
from tkinter import ttk
from collections import defaultdict
def combine_similar_files(selected_file):
"""合并與選定文件類似的所有Excel文件"""
try:
file_dir = os.path.dirname(selected_file)
file_name = os.path.basename(selected_file)
# 獲取目錄下所有Excel文件
listdir = os.listdir(file_dir)
excel_files = [f for f in listdir if f.endswith(('.xlsx', '.xls'))]
if not excel_files:
messagebox.showerror("錯(cuò)誤", "目錄中沒有找到 Excel 文件!")
return
# 分析選定文件的特征(文件名模式)
base_name = file_name
# 嘗試提取共同前綴(去除序號(hào)、版本號(hào)等)
common_patterns = extract_common_pattern(base_name)
# 根據(jù)特征篩選相似文件
similar_files = find_similar_files(excel_files, common_patterns, base_name)
if len(similar_files) <= 1:
messagebox.showinfo("提示", f"沒有找到與 '{file_name}' 相似的其他文件")
return
# 顯示找到的相似文件列表
file_list = "\n".join(similar_files)
confirm = messagebox.askyesno(
"確認(rèn)合并",
f"找到以下相似文件,是否合并?\n\n{file_list}\n\n共 {len(similar_files)} 個(gè)文件"
)
if not confirm:
return
# 合并文件
df_combined = None
for filename in similar_files:
file_path = os.path.join(file_dir, filename)
df_temp = pd.read_excel(file_path)
if df_combined is None:
df_combined = df_temp
else:
# 檢查列結(jié)構(gòu)是否一致
if set(df_combined.columns) != set(df_temp.columns):
# 如果不一致,嘗試對(duì)齊列
df_temp = df_temp.reindex(columns=df_combined.columns, fill_value=None)
df_combined = pd.concat([df_combined, df_temp], ignore_index=True, sort=False)
# 生成輸出文件名
output_name = generate_output_name(common_patterns, base_name)
output_path = os.path.join(file_dir, f"{output_name}_合并結(jié)果.xlsx")
# 避免文件名沖突
counter = 1
while os.path.exists(output_path):
output_path = os.path.join(file_dir, f"{output_name}_合并結(jié)果({counter}).xlsx")
counter += 1
# 保存合并后的文件
df_combined.to_excel(output_path, index=False)
messagebox.showinfo(
"成功",
f"數(shù)據(jù)合并完成!\n"
f"合并了 {len(similar_files)} 個(gè)文件\n"
f"保存位置:{output_path}\n"
f"總行數(shù):{len(df_combined)}"
)
except Exception as e:
messagebox.showerror("錯(cuò)誤", f"合并過程中出現(xiàn)錯(cuò)誤:{str(e)}")
def extract_common_pattern(filename):
"""提取文件名的共同模式"""
# 去除擴(kuò)展名
name_without_ext = os.path.splitext(filename)[0]
patterns = []
# 常見模式識(shí)別
# 1. 按數(shù)字分割(如:文件1.xlsx, 文件2.xlsx)
if any(char.isdigit() for char in name_without_ext):
# 提取非數(shù)字部分作為模式
non_digit_parts = []
current_part = ""
for char in name_without_ext:
if char.isdigit():
if current_part:
non_digit_parts.append(current_part)
current_part = ""
else:
current_part += char
if current_part:
non_digit_parts.append(current_part)
if non_digit_parts:
patterns.append(''.join(non_digit_parts).strip(' _-'))
# 2. 按常見分隔符分割
separators = ['_', '-', ' ']
for sep in separators:
if sep in name_without_ext:
parts = name_without_ext.split(sep)
# 取前面幾個(gè)部分作為模式
if len(parts) > 1:
patterns.append(sep.join(parts[:-1]))
# 3. 如果以上都不適用,使用整個(gè)文件名(不含擴(kuò)展名)
if not patterns:
patterns.append(name_without_ext)
return patterns
def find_similar_files(all_files, patterns, base_file):
"""根據(jù)模式查找相似文件"""
similar_files = [base_file] # 包含選定的文件
for pattern in patterns:
if pattern: # 確保模式不為空
for filename in all_files:
if filename == base_file:
continue # 跳過選定的文件本身
name_without_ext = os.path.splitext(filename)[0]
# 多種匹配策略
if (pattern in filename or
pattern in name_without_ext or
filename.startswith(pattern) or
name_without_ext.startswith(pattern)):
similar_files.append(filename)
# 去重并返回
return list(dict.fromkeys(similar_files))
def generate_output_name(patterns, base_file):
"""生成輸出文件名"""
if patterns:
# 使用最長的模式作為基礎(chǔ)名稱
longest_pattern = max(patterns, key=len)
if len(longest_pattern) > 3: # 確保模式有足夠長度
return longest_pattern
# 回退方案:使用基礎(chǔ)文件名(不含擴(kuò)展名)
return os.path.splitext(base_file)[0]
def select_file():
"""選擇Excel文件"""
file_path = filedialog.askopenfilename(
title="選擇要合并的Excel文件",
filetypes=[("Excel files", "*.xlsx *.xls"), ("All files", "*.*")]
)
if file_path:
file_var.set(file_path)
# 顯示選中的文件名
file_name = os.path.basename(file_path)
info_var.set(f"已選擇: {file_name}")
def start_combine():
"""開始合并"""
file_path = file_var.get()
if not file_path or not os.path.exists(file_path):
messagebox.showwarning("警告", "請(qǐng)先選擇有效的Excel文件!")
return
combine_similar_files(file_path)
# 創(chuàng)建主窗口
root = tk.Tk()
root.title("智能文件合并:數(shù)據(jù)分析")
root.geometry("600x180")
# 變量
file_var = tk.StringVar()
info_var = tk.StringVar(value="請(qǐng)選擇Excel文件")
# 界面布局
frame = ttk.Frame(root, padding="15")
frame.grid(row=0, column=0, sticky=(tk.W, tk.E, tk.N, tk.S))
# 文件選擇行
ttk.Label(frame, text="選擇基準(zhǔn)Excel文件:").grid(row=0, column=0, sticky=tk.W, pady=5)
ttk.Entry(frame, textvariable=file_var, width=50).grid(row=0, column=1, padx=5, pady=5)
ttk.Button(frame, text="瀏覽", command=select_file).grid(row=0, column=2, padx=5, pady=5)
# 文件信息顯示
ttk.Label(frame, textvariable=info_var, foreground="blue").grid(row=1, column=1, sticky=tk.W, pady=5)
# 說明文字
info_text = "系統(tǒng)會(huì)自動(dòng)查找與選定文件相似的其他文件進(jìn)行合并\n(基于文件名模式識(shí)別,如:文件1.xlsx, 文件2.xlsx)"
ttk.Label(frame, text=info_text, foreground="gray", font=("Arial", 9)).grid(row=2, column=1, sticky=tk.W, pady=5)
# 開始合并按鈕
ttk.Button(frame, text="開始智能合并", command=start_combine).grid(row=3, column=1, pady=15)
# 配置網(wǎng)格權(quán)重
root.columnconfigure(0, weight=1)
root.rowconfigure(0, weight=1)
frame.columnconfigure(1, weight=1)
root.mainloop()
整合代碼
import pandas as pd
import os
import tkinter as tk
from tkinter import filedialog, messagebox
from tkinter import ttk
import math
import logging
import sys
# --- 1. 日志配置 ---
# 配置日志輸出到控制臺(tái) (CMD) 和文件,用于調(diào)試和運(yùn)行狀態(tài)跟蹤
def setup_logging():
# 使用 StreamHandler 將日志輸出到標(biāo)準(zhǔn)輸出,確保在 CMD 中可見
logging.basicConfig(
level=logging.INFO, # 默認(rèn)級(jí)別為 INFO,會(huì)輸出 INFO, WARNING, ERROR, CRITICAL
format='%(asctime)s - %(levelname)s - %(message)s',
handlers=[
logging.StreamHandler(sys.stdout)
]
)
logging.info("日志初始化完成。Excel 處理工具啟動(dòng)。")
# --- 2. 文件合并邏輯 (Merge Functions) ---
def extract_common_pattern(filename):
"""提取文件名的共同模式(用于智能識(shí)別相似文件)"""
name_without_ext = os.path.splitext(filename)[0]
logging.debug(f"分析文件名模式: {name_without_ext}")
patterns = []
# 1. 按數(shù)字分割(提取非數(shù)字部分作為模式)
non_digit_parts = []
current_part = ""
for char in name_without_ext:
if char.isdigit():
if current_part:
non_digit_parts.append(current_part)
current_part = ""
else:
current_part += char
if current_part:
non_digit_parts.append(current_part)
pattern1 = ''.join(non_digit_parts).strip(' _-')
if pattern1:
patterns.append(pattern1)
logging.debug(f"模式 1 (非數(shù)字部分): {pattern1}")
# 2. 按常見分隔符分割(提取前綴)
separators = ['_', '-']
for sep in separators:
if sep in name_without_ext:
parts = name_without_ext.split(sep)
if len(parts) > 1:
pattern2 = sep.join(parts[:-1]).strip()
if pattern2:
patterns.append(pattern2)
logging.debug(f"模式 2 (分隔符 '{sep}' 前綴): {pattern2}")
# 3. 回退方案:使用整個(gè)文件名(不含擴(kuò)展名)
if not patterns:
patterns.append(name_without_ext)
return list(set(patterns))
def find_similar_files(all_files, patterns, base_file):
"""根據(jù)提取的模式查找相似文件"""
similar_files = [base_file]
logging.info(f"基準(zhǔn)文件: {base_file}")
for pattern in patterns:
logging.debug(f"檢查模式: '{pattern}'")
if not pattern:
continue
for filename in all_files:
if filename == base_file:
continue
name_without_ext = os.path.splitext(filename)[0]
# 匹配邏輯:文件名中包含模式,或文件名以模式開頭
if (pattern in name_without_ext or
name_without_ext.startswith(pattern)):
if filename not in similar_files:
similar_files.append(filename)
logging.info(f"找到相似文件: {filename}")
return list(dict.fromkeys(similar_files))
def generate_output_name(patterns, base_file):
"""生成輸出文件名"""
# 優(yōu)先使用最長的、有意義的模式
meaningful_patterns = [p for p in patterns if len(p) > 3]
if meaningful_patterns:
longest_pattern = max(meaningful_patterns, key=len)
return longest_pattern
# 回退到基準(zhǔn)文件名(不含擴(kuò)展名)
return os.path.splitext(base_file)[0]
def combine_similar_files(selected_file):
"""執(zhí)行文件合并操作的核心邏輯"""
logging.info("-" * 50)
logging.info(f"開始合并操作,基準(zhǔn)文件: {selected_file}")
try:
file_dir = os.path.dirname(selected_file)
file_name = os.path.basename(selected_file)
# 1. 查找所有 Excel 文件
listdir = os.listdir(file_dir)
excel_files = [f for f in listdir if f.lower().endswith(('.xlsx', '.xls', '.xlsm'))]
if not excel_files:
logging.error("目錄中未找到 Excel 文件。")
messagebox.showerror("錯(cuò)誤", "目錄中沒有找到 Excel 文件!")
return
# 2. 分析模式并查找相似文件
common_patterns = extract_common_pattern(file_name)
similar_files = find_similar_files(excel_files, common_patterns, file_name)
if len(similar_files) <= 1:
logging.warning("未找到相似的其他文件。")
messagebox.showinfo("提示", f"沒有找到與 '{file_name}' 相似的其他文件")
return
# 3. 確認(rèn)合并
file_list = "\n".join(similar_files)
logging.info(f"共找到 {len(similar_files)} 個(gè)文件準(zhǔn)備合并。")
confirm = messagebox.askyesno(
"確認(rèn)合并",
f"找到以下相似文件,是否合并?\n\n{file_list}\n\n共 {len(similar_files)} 個(gè)文件"
)
if not confirm:
logging.info("用戶取消了合并操作。")
return
# 4. 執(zhí)行合并
df_combined = pd.DataFrame()
for filename in similar_files:
file_path = os.path.join(file_dir, filename)
logging.info(f"正在讀取文件: {filename}")
try:
# 使用 openpyxl 引擎處理 .xlsx 文件
df_temp = pd.read_excel(file_path, engine='openpyxl')
df_combined = pd.concat([df_combined, df_temp], ignore_index=True, sort=False)
logging.debug(f"文件 {filename} 讀取成功,已合并。")
except Exception as read_e:
logging.error(f"讀取文件 {filename} 時(shí)出錯(cuò): {str(read_e)}")
messagebox.showwarning("文件讀取警告", f"無法讀取文件 '{filename}'。該文件將被跳過。")
continue
if df_combined.empty:
messagebox.showerror("錯(cuò)誤", "所有文件讀取失敗,無法合并。")
logging.error("合并后的 DataFrame 為空。")
return
# 5. 保存結(jié)果
output_name = generate_output_name(common_patterns, file_name)
output_path = os.path.join(file_dir, f"{output_name}_合并結(jié)果.xlsx")
# 避免文件名沖突
counter = 1
while os.path.exists(output_path):
output_path = os.path.join(file_dir, f"{output_name}_合并結(jié)果({counter}).xlsx")
counter += 1
logging.info(f"保存合并結(jié)果到: {output_path}")
df_combined.to_excel(output_path, index=False, engine='openpyxl')
messagebox.showinfo(
"成功",
f"數(shù)據(jù)合并完成!\n合并了 {len(similar_files)} 個(gè)文件\n保存位置:{output_path}\n總行數(shù):{len(df_combined)}"
)
logging.info(f"合并成功,總行數(shù): {len(df_combined)}")
except Exception as e:
logging.critical(f"合并過程中發(fā)生致命錯(cuò)誤: {str(e)}")
messagebox.showerror("錯(cuò)誤", f"合并過程中出現(xiàn)錯(cuò)誤:{str(e)}")
# --- 3. 文件拆分邏輯 (Split Functions) ---
def split_excel(file_path, rows_per_file):
"""執(zhí)行文件拆分操作的核心邏輯"""
logging.info("-" * 50)
logging.info(f"開始拆分操作,文件: {file_path}")
logging.info(f"每份文件行數(shù): {rows_per_file}")
try:
df = pd.read_excel(file_path, engine='openpyxl')
total_rows = len(df)
if total_rows == 0:
messagebox.showerror("錯(cuò)誤", "Excel文件中沒有數(shù)據(jù)!")
logging.error("待拆分文件為空。")
return
# 計(jì)算文件數(shù)量
num_files = math.ceil(total_rows / rows_per_file)
file_dir = os.path.dirname(file_path)
file_name = os.path.splitext(os.path.basename(file_path))[0]
logging.info(f"總行數(shù): {total_rows} 行,將拆分成 {num_files} 個(gè)文件。")
# 拆分和保存
for i in range(num_files):
start_row = i * rows_per_file
end_row = min((i + 1) * rows_per_file, total_rows)
df_subset = df.iloc[start_row:end_row]
output_filename = f"{file_name}_拆分_{i+1}.xlsx"
output_path = os.path.join(file_dir, output_filename)
logging.info(f"保存第 {i+1}/{num_files} 份文件 (行 {start_row+1} 到 {end_row}) 到: {output_path}")
df_subset.to_excel(output_path, index=False, engine='openpyxl')
logging.info(f"文件拆分操作成功完成。")
messagebox.showinfo("成功", f"文件拆分完成!\n共拆分成 {num_files} 個(gè)文件\n每個(gè)文件約 {rows_per_file} 行")
except Exception as e:
logging.critical(f"拆分過程中發(fā)生致命錯(cuò)誤: {str(e)}")
messagebox.showerror("錯(cuò)誤", f"拆分過程中出現(xiàn)錯(cuò)誤:{str(e)}")
# --- 4. Tkinter GUI 界面 ---
class ExcelProcessorApp:
def __init__(self, root):
self.root = root
self.root.title("Excel文件智能處理工具 (合并與拆分)")
# 優(yōu)化界面樣式
try:
style = ttk.Style()
style.theme_use('vista') # 嘗試使用Windows風(fēng)格主題
style.configure('TButton', font=('Arial', 10, 'bold'), padding=6)
except:
pass # 如果主題不存在,保持默認(rèn)
self.root.geometry("650x300")
self.root.resizable(False, False)
# 變量初始化
self.merge_file_var = tk.StringVar()
self.merge_info_var = tk.StringVar(value="請(qǐng)選擇Excel文件作為合并基準(zhǔn)")
self.split_file_var = tk.StringVar()
self.split_rows_var = tk.StringVar(value="10000")
self.split_info_var = tk.StringVar(value="請(qǐng)選擇待拆分的Excel文件")
# 初始化日志
setup_logging()
# 創(chuàng)建 Notebook (標(biāo)簽頁界面)
self.notebook = ttk.Notebook(root)
self.notebook.pack(pady=10, padx=10, expand=True, fill="both")
# 創(chuàng)建標(biāo)簽頁框架
self.merge_frame = ttk.Frame(self.notebook, padding="15 15 15 15")
self.split_frame = ttk.Frame(self.notebook, padding="15 15 15 15")
self.notebook.add(self.merge_frame, text="文件智能合并")
self.notebook.add(self.split_frame, text="文件按行拆分")
# 構(gòu)建標(biāo)簽頁 UI
self._build_merge_tab()
self._build_split_tab()
# --- UI 構(gòu)建器 ---
def _build_merge_tab(self):
self.merge_frame.columnconfigure(1, weight=1)
# 1. 文件選擇
ttk.Label(self.merge_frame, text="選擇基準(zhǔn)Excel文件:", font=('Arial', 10, 'bold')).grid(row=0, column=0, sticky=tk.W, pady=10)
ttk.Entry(self.merge_frame, textvariable=self.merge_file_var, width=50).grid(row=0, column=1, padx=5, pady=10, sticky=(tk.W, tk.E))
ttk.Button(self.merge_frame, text="瀏覽", command=self._select_merge_file).grid(row=0, column=2, padx=5, pady=10)
# 2. 文件信息
ttk.Label(self.merge_frame, textvariable=self.merge_info_var, foreground="#0056b3", font=("Arial", 10)).grid(row=1, column=1, sticky=tk.W, pady=5)
# 3. 功能說明
info_text = "功能說明:系統(tǒng)將根據(jù)文件名模式(例如:文件_1, 文件_2)自動(dòng)查找同目錄下所有相似文件,并將它們合并。\n請(qǐng)確保所有文件的表頭結(jié)構(gòu)大致一致。"
ttk.Label(self.merge_frame, text=info_text, foreground="gray", font=("Arial", 9)).grid(row=2, column=0, columnspan=3, sticky=tk.W, pady=10)
# 4. 開始按鈕
ttk.Button(self.merge_frame, text="? 開始智能合并 ?", command=self._start_merge, style='TButton').grid(row=3, column=1, pady=20)
def _build_split_tab(self):
self.split_frame.columnconfigure(1, weight=1)
# 1. 文件選擇
ttk.Label(self.split_frame, text="選擇待拆分的Excel文件:", font=('Arial', 10, 'bold')).grid(row=0, column=0, sticky=tk.W, pady=10)
ttk.Entry(self.split_frame, textvariable=self.split_file_var, width=50).grid(row=0, column=1, padx=5, pady=10, sticky=(tk.W, tk.E))
ttk.Button(self.split_frame, text="瀏覽", command=self._select_split_file).grid(row=0, column=2, padx=5, pady=10)
# 2. 文件信息
ttk.Label(self.split_frame, textvariable=self.split_info_var, foreground="#0056b3", font=("Arial", 10)).grid(row=1, column=1, sticky=tk.W, pady=5)
# 3. 行數(shù)設(shè)置
ttk.Label(self.split_frame, text="每份文件行數(shù):").grid(row=2, column=0, sticky=tk.W, pady=10)
ttk.Entry(self.split_frame, textvariable=self.split_rows_var, width=15).grid(row=2, column=1, sticky=tk.W, padx=5, pady=10)
ttk.Label(self.split_frame, text="行 (默認(rèn) 10000)").grid(row=2, column=1, sticky=tk.W, padx=120, pady=10)
# 4. 開始按鈕
ttk.Button(self.split_frame, text="?? 開始拆分 ??", command=self._start_split, style='TButton').grid(row=3, column=1, pady=20)
# --- 5. 事件處理器 ---
def _select_file(self, file_var, info_var, mode="select"):
"""通用文件選擇邏輯,并自動(dòng)讀取文件信息(總行數(shù))"""
title = "選擇 Excel 文件"
file_path = filedialog.askopenfilename(
title=title,
filetypes=[("Excel files", "*.xlsx *.xls *.xlsm"), ("All files", "*.*")]
)
if file_path:
file_var.set(file_path)
file_name = os.path.basename(file_path)
try:
# 嘗試讀取文件行數(shù)
df = pd.read_excel(file_path, engine='openpyxl')
total_rows = len(df)
if mode == "split":
info_var.set(f"已選擇: {file_name} | 文件總行數(shù): {total_rows} 行")
logging.info(f"拆分文件已選擇: {file_path}. 總行數(shù): {total_rows}")
else:
info_var.set(f"已選擇: {file_name} | 總行數(shù): {total_rows} 行")
logging.info(f"合并基準(zhǔn)文件已選擇: {file_path}. 總行數(shù): {total_rows}")
except Exception as e:
info_var.set(f"已選擇: {file_name} | 無法讀取文件信息或文件損壞。")
logging.error(f"讀取文件信息出錯(cuò): {e}")
def _select_merge_file(self):
self._select_file(self.merge_file_var, self.merge_info_var, mode="merge")
def _select_split_file(self):
self._select_file(self.split_file_var, self.split_info_var, mode="split")
def _start_merge(self):
file_path = self.merge_file_var.get()
if not file_path or not os.path.exists(file_path):
messagebox.showwarning("警告", "請(qǐng)先選擇有效的Excel文件!")
return
# 運(yùn)行合并邏輯
combine_similar_files(file_path)
def _start_split(self):
file_path = self.split_file_var.get()
if not file_path or not os.path.exists(file_path):
messagebox.showwarning("警告", "請(qǐng)先選擇有效的Excel文件!")
return
try:
rows_per_file = int(self.split_rows_var.get())
if rows_per_file <= 0:
messagebox.showwarning("警告", "請(qǐng)輸入有效的行數(shù)(大于0)!")
return
except ValueError:
messagebox.showwarning("警告", "每份文件行數(shù)必須是有效的數(shù)字!")
return
# 運(yùn)行拆分邏輯
split_excel(file_path, rows_per_file)
# --- 6. 主程序入口 ---
if __name__ == '__main__':
root = tk.Tk()
app = ExcelProcessorApp(root)
root.mainloop()
執(zhí)行打包命令
pyinstaller --onefile --console --upx-dir D:\upx excel_tool.py
以上就是基于Python實(shí)現(xiàn)excel拆分和合并工具并打包的詳細(xì)內(nèi)容,更多關(guān)于Python excel拆分和合并的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
tensorflow mnist 數(shù)據(jù)加載實(shí)現(xiàn)并畫圖效果
TensorFlow™ 是一個(gè)采用數(shù)據(jù)流圖(data flow graphs),用于數(shù)值計(jì)算的開源軟件庫。這篇文章給大家介紹tensorflow mnist 數(shù)據(jù)加載實(shí)現(xiàn)并畫圖效果,感興趣的朋友一起看看吧2020-02-02
Python Pandas中創(chuàng)建Series的三種方法總結(jié)
這篇文章主要介紹了Python Pandas中創(chuàng)建Series的三種方法總結(jié),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-06-06
對(duì)python中的乘法dot和對(duì)應(yīng)分量相乘multiply詳解
今天小編就為大家分享一篇對(duì)python中的乘法dot和對(duì)應(yīng)分量相乘multiply詳解,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2018-11-11
python實(shí)現(xiàn)linux下使用xcopy的方法
這篇文章主要介紹了python實(shí)現(xiàn)linux下使用xcopy的方法,可實(shí)現(xiàn)模仿windows下的xcopy命令功能,需要的朋友可以參考下2015-06-06
Python退出While循環(huán)的3種方法舉例詳解
在每次循環(huán)結(jié)束后,我們需要檢查循環(huán)條件是否滿足。如果條件滿足,則繼續(xù)執(zhí)行循環(huán)體內(nèi)的代碼,否則退出循環(huán),這篇文章主要給大家介紹了關(guān)于Python退出While循環(huán)的3種方法,需要的朋友可以參考下2023-10-10
Python腳本實(shí)現(xiàn)掃描網(wǎng)站子域名及漏洞
這篇文章主要為大家詳細(xì)介紹了如何使用Python編寫一個(gè)域名漏洞掃描腳本,可以實(shí)現(xiàn)子域名枚舉,端口掃描,服務(wù)識(shí)別和常見漏洞檢測,感興趣的小伙伴可以了解下2025-12-12
Python使用ftplib實(shí)現(xiàn)簡易FTP客戶端的方法
這篇文章主要介紹了Python使用ftplib實(shí)現(xiàn)簡易FTP客戶端的方法,實(shí)例分析了ftplib模塊相關(guān)設(shè)置與使用技巧,需要的朋友可以參考下2015-06-06
Python異常處理機(jī)制結(jié)構(gòu)實(shí)例解析
這篇文章主要介紹了Python異常處理機(jī)制結(jié)構(gòu)實(shí)例解析,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-07-07

