From 1dffb8132596f42e6ef8ee4d2a9276a64c281a0f Mon Sep 17 00:00:00 2001 From: Developer Date: Thu, 20 Nov 2025 12:10:18 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=9E=E7=8E=B0Excel=E5=90=88=E5=B9=B6?= =?UTF-8?q?=E5=B7=A5=E5=85=B7=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 添加EPPlus NuGet包用于Excel文件处理 - 设计完整的UI界面(文件夹选择、按钮、进度条、日志显示) - 实现Excel文件合并核心逻辑,支持多个xlsx文件合并 - 添加错误处理和进度跟踪功能 - 提供用户友好的操作界面和提示信息 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- WinFormsApp1/Form1.Designer.cs | 135 ++++++++++++++++- WinFormsApp1/Form1.cs | 239 +++++++++++++++++++++++++++++++ WinFormsApp1/WinFormsApp1.csproj | 4 + 3 files changed, 376 insertions(+), 2 deletions(-) diff --git a/WinFormsApp1/Form1.Designer.cs b/WinFormsApp1/Form1.Designer.cs index f4907b9..55e8dde 100644 --- a/WinFormsApp1/Form1.Designer.cs +++ b/WinFormsApp1/Form1.Designer.cs @@ -29,11 +29,142 @@ private void InitializeComponent() { components = new System.ComponentModel.Container(); + + // 主窗体设置 AutoScaleMode = AutoScaleMode.Font; - ClientSize = new Size(800, 450); - Text = "Form1"; + ClientSize = new Size(600, 400); + Text = "Excel合并工具"; + StartPosition = FormStartPosition.CenterScreen; + + // 创建控件 + grpSourceFolder = new GroupBox(); + lblSourcePath = new Label(); + txtSourcePath = new TextBox(); + btnBrowseSource = new Button(); + + grpOutputFolder = new GroupBox(); + lblOutputPath = new Label(); + txtOutputPath = new TextBox(); + btnBrowseOutput = new Button(); + + pnlButtons = new Panel(); + btnMerge = new Button(); + btnClear = new Button(); + btnExit = new Button(); + + grpProgress = new GroupBox(); + progressBar = new ProgressBar(); + txtLog = new TextBox(); + + // 设置源文件夹组 + grpSourceFolder.Text = "源文件夹"; + grpSourceFolder.Location = new Point(10, 10); + grpSourceFolder.Size = new Size(580, 60); + grpSourceFolder.TabStop = false; + + lblSourcePath.Text = "路径:"; + lblSourcePath.Location = new Point(10, 25); + lblSourcePath.Size = new Size(30, 23); + + txtSourcePath.Location = new Point(45, 22); + txtSourcePath.Size = new Size(470, 23); + + btnBrowseSource.Text = "浏览"; + btnBrowseSource.Location = new Point(520, 20); + btnBrowseSource.Size = new Size(50, 25); + btnBrowseSource.Click += new EventHandler(btnBrowseSource_Click); + + grpSourceFolder.Controls.Add(lblSourcePath); + grpSourceFolder.Controls.Add(txtSourcePath); + grpSourceFolder.Controls.Add(btnBrowseSource); + + // 设置输出文件夹组 + grpOutputFolder.Text = "输出文件夹"; + grpOutputFolder.Location = new Point(10, 80); + grpOutputFolder.Size = new Size(580, 60); + grpOutputFolder.TabStop = false; + + lblOutputPath.Text = "路径:"; + lblOutputPath.Location = new Point(10, 25); + lblOutputPath.Size = new Size(30, 23); + + txtOutputPath.Location = new Point(45, 22); + txtOutputPath.Size = new Size(470, 23); + + btnBrowseOutput.Text = "浏览"; + btnBrowseOutput.Location = new Point(520, 20); + btnBrowseOutput.Size = new Size(50, 25); + btnBrowseOutput.Click += new EventHandler(btnBrowseOutput_Click); + + grpOutputFolder.Controls.Add(lblOutputPath); + grpOutputFolder.Controls.Add(txtOutputPath); + grpOutputFolder.Controls.Add(btnBrowseOutput); + + // 设置按钮面板 + pnlButtons.Location = new Point(10, 150); + pnlButtons.Size = new Size(580, 40); + + btnMerge.Text = "合并"; + btnMerge.Location = new Point(10, 8); + btnMerge.Size = new Size(75, 25); + btnMerge.Click += new EventHandler(btnMerge_Click); + + btnClear.Text = "清空"; + btnClear.Location = new Point(100, 8); + btnClear.Size = new Size(75, 25); + btnClear.Click += new EventHandler(btnClear_Click); + + btnExit.Text = "退出"; + btnExit.Location = new Point(190, 8); + btnExit.Size = new Size(75, 25); + btnExit.Click += new EventHandler(btnExit_Click); + + pnlButtons.Controls.Add(btnMerge); + pnlButtons.Controls.Add(btnClear); + pnlButtons.Controls.Add(btnExit); + + // 设置进度组 + grpProgress.Text = "进度"; + grpProgress.Location = new Point(10, 200); + grpProgress.Size = new Size(580, 180); + grpProgress.TabStop = false; + + progressBar.Location = new Point(10, 25); + progressBar.Size = new Size(560, 23); + progressBar.Style = ProgressBarStyle.Continuous; + + txtLog.Location = new Point(10, 55); + txtLog.Size = new Size(560, 115); + txtLog.Multiline = true; + txtLog.ScrollBars = ScrollBars.Vertical; + txtLog.ReadOnly = true; + + grpProgress.Controls.Add(progressBar); + grpProgress.Controls.Add(txtLog); + + // 添加所有控件到窗体 + Controls.Add(grpSourceFolder); + Controls.Add(grpOutputFolder); + Controls.Add(pnlButtons); + Controls.Add(grpProgress); } #endregion + + private GroupBox grpSourceFolder; + private Label lblSourcePath; + private TextBox txtSourcePath; + private Button btnBrowseSource; + private GroupBox grpOutputFolder; + private Label lblOutputPath; + private TextBox txtOutputPath; + private Button btnBrowseOutput; + private Panel pnlButtons; + private Button btnMerge; + private Button btnClear; + private Button btnExit; + private GroupBox grpProgress; + private ProgressBar progressBar; + private TextBox txtLog; } } diff --git a/WinFormsApp1/Form1.cs b/WinFormsApp1/Form1.cs index dabe0d0..16b2e0a 100644 --- a/WinFormsApp1/Form1.cs +++ b/WinFormsApp1/Form1.cs @@ -6,5 +6,244 @@ namespace WinFormsApp1 { InitializeComponent(); } + + 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; + + var allData = new List(); + var headers = new List(); + + 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]; // 使用第一个工作表 + var table = new System.Data.DataTable(); + + // 获取表头 + 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) + { + foreach (System.Data.DataRow row in table.Rows) + { + 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(); + } } } diff --git a/WinFormsApp1/WinFormsApp1.csproj b/WinFormsApp1/WinFormsApp1.csproj index c27cd77..b5e02da 100644 --- a/WinFormsApp1/WinFormsApp1.csproj +++ b/WinFormsApp1/WinFormsApp1.csproj @@ -8,4 +8,8 @@ enable + + + + \ No newline at end of file