2025-11-20 14:23:05 +08:00
|
|
|
|
using System;
|
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
|
using System.IO;
|
|
|
|
|
|
using System.Linq;
|
|
|
|
|
|
using System.Windows.Forms;
|
|
|
|
|
|
using System.Data;
|
|
|
|
|
|
|
2025-11-20 11:10:53 +08:00
|
|
|
|
namespace WinFormsApp1
|
|
|
|
|
|
{
|
|
|
|
|
|
public partial class Form1 : Form
|
|
|
|
|
|
{
|
|
|
|
|
|
public Form1()
|
|
|
|
|
|
{
|
|
|
|
|
|
InitializeComponent();
|
|
|
|
|
|
}
|
2025-11-20 12:10:18 +08:00
|
|
|
|
|
|
|
|
|
|
private void btnBrowseSource_Click(object sender, EventArgs e)
|
|
|
|
|
|
{
|
|
|
|
|
|
using (FolderBrowserDialog dialog = new FolderBrowserDialog())
|
|
|
|
|
|
{
|
|
|
|
|
|
dialog.Description = "选择Excel文件夹";
|
|
|
|
|
|
if (dialog.ShowDialog() == DialogResult.OK)
|
|
|
|
|
|
{
|
|
|
|
|
|
txtSourcePath.Text = dialog.SelectedPath;
|
|
|
|
|
|
txtOutputPath.Text = dialog.SelectedPath; // 默认输出到源文件夹
|
|
|
|
|
|
Log($"源文件夹: {dialog.SelectedPath}");
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void btnBrowseOutput_Click(object sender, EventArgs e)
|
|
|
|
|
|
{
|
|
|
|
|
|
using (FolderBrowserDialog dialog = new FolderBrowserDialog())
|
|
|
|
|
|
{
|
|
|
|
|
|
dialog.Description = "选择输出文件夹";
|
|
|
|
|
|
if (dialog.ShowDialog() == DialogResult.OK)
|
|
|
|
|
|
{
|
|
|
|
|
|
txtOutputPath.Text = dialog.SelectedPath;
|
|
|
|
|
|
Log($"输出文件夹: {dialog.SelectedPath}");
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void btnClear_Click(object sender, EventArgs e)
|
|
|
|
|
|
{
|
|
|
|
|
|
txtSourcePath.Clear();
|
|
|
|
|
|
txtOutputPath.Clear();
|
|
|
|
|
|
txtLog.Clear();
|
|
|
|
|
|
progressBar.Value = 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void btnExit_Click(object sender, EventArgs e)
|
|
|
|
|
|
{
|
|
|
|
|
|
Application.Exit();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void btnMerge_Click(object sender, EventArgs e)
|
|
|
|
|
|
{
|
|
|
|
|
|
// 前置校验
|
|
|
|
|
|
if (string.IsNullOrEmpty(txtSourcePath.Text) || string.IsNullOrEmpty(txtOutputPath.Text))
|
|
|
|
|
|
{
|
|
|
|
|
|
MessageBox.Show("请选择源文件夹和输出文件夹", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
MergeExcel();
|
|
|
|
|
|
}
|
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
|
{
|
|
|
|
|
|
MessageBox.Show($"合并过程中发生错误: {ex.Message}", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
|
|
|
|
|
Log($"合并失败: {ex.Message}");
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void MergeExcel()
|
|
|
|
|
|
{
|
|
|
|
|
|
var sourceDir = txtSourcePath.Text;
|
|
|
|
|
|
var outputDir = txtOutputPath.Text;
|
|
|
|
|
|
var outputFile = Path.Combine(outputDir, "合并结果.xlsx");
|
|
|
|
|
|
|
|
|
|
|
|
if (!Directory.Exists(sourceDir))
|
|
|
|
|
|
{
|
|
|
|
|
|
MessageBox.Show("源文件夹不存在", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 查找xlsx文件(排除合并结果本身)
|
|
|
|
|
|
var xlsxFiles = Directory.GetFiles(sourceDir, "*.xlsx")
|
|
|
|
|
|
.Where(f => !Path.GetFileName(f).Equals("合并结果.xlsx", StringComparison.OrdinalIgnoreCase))
|
|
|
|
|
|
.ToArray();
|
|
|
|
|
|
|
|
|
|
|
|
if (xlsxFiles.Length == 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
MessageBox.Show("未找到待合并的Excel文件", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Log($"找到 {xlsxFiles.Length} 个文件,开始合并...");
|
|
|
|
|
|
progressBar.Maximum = xlsxFiles.Length;
|
|
|
|
|
|
progressBar.Value = 0;
|
|
|
|
|
|
|
|
|
|
|
|
// 设置EPPlus许可证上下文
|
|
|
|
|
|
OfficeOpenXml.ExcelPackage.LicenseContext = OfficeOpenXml.LicenseContext.NonCommercial;
|
|
|
|
|
|
|
2025-11-20 14:23:05 +08:00
|
|
|
|
var allData = new List<DataTable>();
|
2025-11-20 12:10:18 +08:00
|
|
|
|
var headers = new List<string>();
|
|
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
// 处理每个文件
|
|
|
|
|
|
for (int idx = 0; idx < xlsxFiles.Length; idx++)
|
|
|
|
|
|
{
|
|
|
|
|
|
var file = xlsxFiles[idx];
|
|
|
|
|
|
var fileName = Path.GetFileName(file);
|
|
|
|
|
|
|
|
|
|
|
|
Log($"处理: {fileName}");
|
|
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
using (var package = new OfficeOpenXml.ExcelPackage(new FileInfo(file)))
|
|
|
|
|
|
{
|
|
|
|
|
|
if (package.Workbook.Worksheets.Count == 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
Log($"跳过空文件: {fileName}");
|
|
|
|
|
|
continue;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
var worksheet = package.Workbook.Worksheets[0]; // 使用第一个工作表
|
2025-11-20 14:23:05 +08:00
|
|
|
|
var table = new DataTable();
|
2025-11-20 12:10:18 +08:00
|
|
|
|
|
|
|
|
|
|
// 获取表头
|
|
|
|
|
|
if (headers.Count == 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
var columnCount = worksheet.Dimension.End.Column;
|
|
|
|
|
|
for (int col = 1; col <= columnCount; col++)
|
|
|
|
|
|
{
|
|
|
|
|
|
var header = worksheet.Cells[1, col].Text?.Trim() ?? $"Column{col}";
|
|
|
|
|
|
headers.Add(header);
|
|
|
|
|
|
table.Columns.Add(header);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
// 创建相同结构的表
|
|
|
|
|
|
foreach (var header in headers)
|
|
|
|
|
|
{
|
|
|
|
|
|
table.Columns.Add(header);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 跳过表头行,从第二行开始读取数据
|
|
|
|
|
|
var rowCount = worksheet.Dimension.End.Row;
|
|
|
|
|
|
for (int row = 2; row <= rowCount; row++)
|
|
|
|
|
|
{
|
|
|
|
|
|
var dataRow = table.NewRow();
|
|
|
|
|
|
var isEmpty = true;
|
|
|
|
|
|
|
|
|
|
|
|
for (int col = 0; col < headers.Count; col++)
|
|
|
|
|
|
{
|
|
|
|
|
|
var cellValue = worksheet.Cells[row, col + 1].Text;
|
|
|
|
|
|
dataRow[col] = cellValue;
|
|
|
|
|
|
if (!string.IsNullOrWhiteSpace(cellValue))
|
|
|
|
|
|
{
|
|
|
|
|
|
isEmpty = false;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (!isEmpty)
|
|
|
|
|
|
{
|
|
|
|
|
|
table.Rows.Add(dataRow);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (table.Rows.Count > 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
allData.Add(table);
|
|
|
|
|
|
Log($"成功读取 {fileName}: {table.Rows.Count} 行数据");
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
Log($"跳过无数据文件: {fileName}");
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
|
{
|
|
|
|
|
|
Log($"处理失败: {fileName} - {ex.Message}");
|
|
|
|
|
|
continue;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
progressBar.Value = idx + 1;
|
|
|
|
|
|
Application.DoEvents();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 合并数据并保存
|
|
|
|
|
|
if (allData.Count == 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
MessageBox.Show("无有效数据可合并", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 创建合并后的Excel文件
|
|
|
|
|
|
using (var outputPackage = new OfficeOpenXml.ExcelPackage())
|
|
|
|
|
|
{
|
|
|
|
|
|
var outputSheet = outputPackage.Workbook.Worksheets.Add("合并结果");
|
|
|
|
|
|
|
|
|
|
|
|
// 写入表头
|
|
|
|
|
|
for (int col = 0; col < headers.Count; col++)
|
|
|
|
|
|
{
|
|
|
|
|
|
outputSheet.Cells[1, col + 1].Value = headers[col];
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int currentRow = 2;
|
|
|
|
|
|
int totalRows = 0;
|
|
|
|
|
|
|
|
|
|
|
|
// 合并所有数据
|
|
|
|
|
|
foreach (var table in allData)
|
|
|
|
|
|
{
|
2025-11-20 14:23:05 +08:00
|
|
|
|
foreach (DataRow row in table.Rows)
|
2025-11-20 12:10:18 +08:00
|
|
|
|
{
|
|
|
|
|
|
for (int col = 0; col < headers.Count; col++)
|
|
|
|
|
|
{
|
|
|
|
|
|
outputSheet.Cells[currentRow, col + 1].Value = row[col];
|
|
|
|
|
|
}
|
|
|
|
|
|
currentRow++;
|
|
|
|
|
|
totalRows++;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 保存文件
|
|
|
|
|
|
outputPackage.SaveAs(new FileInfo(outputFile));
|
|
|
|
|
|
|
|
|
|
|
|
Log($"合并完成!文件路径: {outputFile}");
|
|
|
|
|
|
Log($"总行数: {totalRows} | 总列数: {headers.Count}");
|
|
|
|
|
|
|
|
|
|
|
|
MessageBox.Show($"合并成功!\n文件:{outputFile}\n行数:{totalRows}",
|
|
|
|
|
|
"完成", MessageBoxButtons.OK, MessageBoxIcon.Information);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
|
{
|
|
|
|
|
|
Log($"保存失败: {ex.Message}");
|
|
|
|
|
|
MessageBox.Show($"保存文件失败: {ex.Message}", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void Log(string msg)
|
|
|
|
|
|
{
|
|
|
|
|
|
txtLog.AppendText($"{msg}\r\n");
|
|
|
|
|
|
txtLog.ScrollToCaret();
|
|
|
|
|
|
Application.DoEvents();
|
|
|
|
|
|
}
|
2025-11-20 11:10:53 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|