界止签章宗地号替换工具

界止签章宗地号替换工具 - 项目文档

项目概述

这是一个 Windows Forms 应用程序,用于批量处理 Word 文档,实现宗地号的批量替换和页眉编号插入功能,并支持导出签章明细表到 Excel。

功能特性

  1. 批量处理 Word 文档

    • 支持递归扫描目录下的所有 .docx 文件
    • 自动替换文档中的宗地号
    • 在文档页眉中插入编号
  2. 多格式宗地号匹配

    • 支持带括号格式:(123123123123JC14008)
    • 支持不带括号格式:123123123123JC14008
    • 支持通配符格式:123123123123J******
  3. 实时处理显示

    • DataGridView 显示处理进度
    • 进度条显示整体进度
    • 显示每个文件的处理详情
  4. Excel 导出功能

    • 导出签章明细表到 Excel
    • 包含文件名、替换编号、状态、替换内容等信息
    • 自动调整列宽
  5. 日志记录

    • 生成详细的处理日志文件
    • 记录每个文件的处理结果
    • 统计处理数据

技术栈

  • 开发框架:.NET 8.0 Windows
  • UI 框架:Windows Forms
  • 文档处理库:DocumentFormat.OpenXml 3.3.0
  • 编程语言:C#

项目结构

复制代码
14界止签章宗地号替换/
├── Form1.cs                 # 主窗体代码
├── Form1.Designer.cs         # 窗体设计器代码
├── Form1.resx               # 窗体资源文件
├── Program.cs               # 程序入口
├── 14界止签章宗地号替换.csproj  # 项目文件
└── 14界止签章宗地号替换.sln     # 解决方案文件

核心类说明

Form1 类

主窗体类,包含所有 UI 逻辑和业务逻辑。

主要字段
csharp 复制代码
private DataTable logTable;              // 存储处理日志的数据表
private const string NEW_LAND_NUMBER = ""; // 新宗地号(待设置)
主要方法
方法名 功能说明
InitializeDataGridView() 初始化 DataGridView 数据表结构
button1_Click() 选择目录并开始批量处理
button2_Click() 导出数据到 Excel
ProcessWordDocumentsAsync() 异步批量处理 Word 文档
ProcessWordDocumentWithHeader() 处理单个 Word 文档
ExtractCodeFromFileName() 从文件名提取编号
ProcessSingleDocumentContent() 替换文档中的宗地号
ProcessElement() 处理文档元素并替换文本
FindAllLandNumbers() 使用正则表达式查找宗地号
CreateHeader() 创建文档页眉
ProcessHeader() 处理现有页眉
AddLogRow() 添加处理记录到 DataGridView
ExportToExcel() 导出数据到 Excel
CreateCellWithInlineString() 创建 Excel 单元格
GetCellReference() 获取 Excel 单元格引用

ProcessResult 类

处理结果数据模型。

csharp 复制代码
public class ProcessResult
{
    public bool Success;                 // 是否成功处理
    public bool WasReplaced;             // 是否执行了替换
    public int ReplaceCount;             // 替换次数
    public string SampleReplacements;     // 替换示例
    public bool HeaderProcessed;          // 是否处理了页眉
    public string ErrorMessage;           // 错误信息
    public List<string> FoundLandNumbers; // 找到的宗地号列表
}

数据结构

DataGridView 列结构

列名 数据类型 说明
序号 int 文件处理序号
文件名 string Word 文档文件名
替换编号 string 所有被替换的宗地号(分号分隔)
状态 string 处理状态(已处理/无匹配/错误)
替换内容 string 详细的替换信息
处理时间 string 处理时间

使用说明

1. 准备工作

  • 打开项目,设置 NEW_LAND_NUMBER 常量为需要替换成的新宗地号
  • 编译并运行程序

2. 处理文档

  1. 点击"选择目录"按钮
  2. 选择包含 Word 文档的目录
  3. 程序自动扫描并处理所有 .docx 文件
  4. 查看处理进度和结果

3. 导出明细

  1. 处理完成后,点击"导出 Excel"按钮
  2. 选择保存位置
  3. 程序生成签章明细表.xlsx 文件

宗地号匹配规则

程序使用正则表达式匹配以下格式的宗地号:

regex 复制代码
(?:\(123123123123J(?:[A-Z0-9]{6}|\*{6})\)|123123123123J(?:[A-Z0-9]{6}|\*{6}))

支持的格式示例

格式 示例
带括号完整格式 (123123123123JC14008)
不带括号格式 123123123123JC14008
带通配符格式 (123123123123J******)
不带括号通配符 123123123123J******

编号提取规则

从文件名中提取编号:

regex 复制代码
123123123123([A-Z0-9]{6,7})

示例:123123123123JC14008-界址签章表.docxJC14008

页眉处理规则

字体样式

  • 字体:宋体
  • 字号:五号(10.5磅)
  • 颜色:灰色(RGB: 128, 128, 128)
  • 对齐方式:右对齐

处理逻辑

  1. 检查文档是否存在页眉
  2. 如果存在,检查是否已包含编号
  3. 如果不存在编号,添加新段落
  4. 如果不存在页眉,创建新页眉并插入编号

Excel 导出格式

文件命名

复制代码
签章明细表_yyyyMMdd_HHmmss.xlsx

工作表结构

列名 说明
序号 文件序号
文件名 Word 文档名称
替换编号 被替换的所有宗地号(分号分隔)
状态 处理状态
替换内容 详细替换信息
处理时间 处理时间(HH:mm:ss)

单元格格式

  • 数据类型:InlineString
  • 列宽:根据内容自动调整(最大 50 字符)

日志文件格式

文件命名

复制代码
宗地号替换日志_yyyyMMdd_HHmmss.txt

日志内容示例

复制代码
=== 宗地号批量替换处理日志 ===
开始处理时间: 2026-01-04 10:30:00
处理目录: D:\Documents\WordFiles
文件总数: 10
替换规则: 所有 (123123123123Jxxxxxx) 格式的宗地号
替换为: NEW_LAND_NUMBER
页眉处理: 插入JC14008 宋体五号灰色
==========================================
[已处理] 123123123123JC14008.docx
  替换数量: 3
  具体内容: (123123123123JC14008) -> NEW_LAND_NUMBER
  页眉处理: 已插入JC14008
==========================================
处理完成时间: 2026-01-04 10:35:00
总文件数: 10
成功处理: 9
已替换文件: 5
替换总数: 15 处
已处理页眉: 8
错误文件: 1

工作流程



用户选择目录
获取所有.docx文件
遍历每个文件
从文件名提取编号
打开Word文档
处理文档内容
查找并替换宗地号
处理页眉
记录替换信息
插入编号到页眉
保存文档
添加记录到DataGridView
还有文件?
处理完成
生成日志文件
显示统计结果
等待用户导出Excel
用户点击导出
生成Excel文件

异步处理机制

程序使用异步处理避免 UI 冻结:

csharp 复制代码
await Task.Run(() => ProcessWordDocumentWithHeader(filePath));

UI 线程安全

从后台线程更新 UI 需要使用 Invoke:

csharp 复制代码
this.Invoke(new Action(() => AddLogRow(...)));

命名空间处理

由于同时引用了 WordprocessingSpreadsheet 命名空间,需要明确指定:

Word 相关类型

csharp 复制代码
DocumentFormat.OpenXml.Wordprocessing.*
  • Paragraph
  • Run
  • Text
  • FontSize
  • Color
  • RunProperties
  • Header

Excel 相关类型

csharp 复制代码
DocumentFormat.OpenXml.Spreadsheet.*
  • Cell
  • Row
  • Column
  • SheetData
  • InlineString

注意事项

  1. 新宗地号设置

    • 需要在代码中手动设置 NEW_LAND_NUMBER 常量
    • 当前为空字符串
  2. 文件备份

    • 程序直接修改原文件
    • 建议处理前备份原始文件
  3. 编码问题

    • 日志文件使用 UTF-8 编码
    • 支持中文文件名和内容
  4. 性能考虑

    • 大批量文件处理可能需要较长时间
    • 建议分批处理(每次不超过 100 个文件)
  5. 错误处理

    • 处理失败的文件会记录在日志中
    • 不会中断其他文件的处理

依赖项

NuGet 包

xml 复制代码
<ItemGroup>
  <PackageReference Include="DocumentFormat.OpenXml" Version="3.3.0" />
</ItemGroup>

系统要求

  • .NET 8.0 Windows Runtime
  • Windows 10 或更高版本
  • Visual Studio 2022 或更高版本(用于开发)

编译和运行

编译项目

bash 复制代码
dotnet build "14界止签章宗地号替换.csproj"

运行项目

bash 复制代码
dotnet run --project "14界止签章宗地号替换.csproj"

或在 Visual Studio 中按 F5 运行。

常见问题

Q1: 为什么导出的 Excel 文件没有内容?

A: 确保 DataGridView 中有数据后再点击导出按钮。

Q2: 替换编号列显示空白?

A: 检查文档中是否有匹配的宗地号格式,以及是否设置了 NEW_LAND_NUMBER。

Q3: 页眉没有正确插入?

A: 确保文件名中包含符合格式的编号(如 123123123123JC14008)。

Q4: 处理速度较慢?

A: 这是正常现象,大量文件处理需要时间,可以查看进度条了解进度。

更新日志

Version 1.0.0 (2026-01-04)

  • 初始版本
  • 支持批量替换宗地号
  • 支持页眉编号插入
  • 支持 Excel 导出
  • 完整的日志记录功能

完整代码

Form1.cs

csharp 复制代码
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
using System.Windows.Forms;
using DocumentFormat.OpenXml;
using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml.Wordprocessing;
using OfficeOpenXml;
using Excel = OfficeOpenXml;
using WordFontSize = DocumentFormat.OpenXml.Wordprocessing.FontSize;
using WordColor = DocumentFormat.OpenXml.Wordprocessing.Color;

namespace _14界止签章宗地号替换
{
    public partial class Form1 : Form
    {
        // 存储处理结果的数据表
        private DataTable resultTable;
        private BackgroundWorker backgroundWorker;
        private int totalFiles;
        private int processedFiles;
        private string currentDirectory;

        public Form1()
        {
            InitializeComponent();
            InitializeDataGridView();
            InitializeBackgroundWorker();
        }

        private void InitializeDataGridView()
        {
            resultTable = new DataTable();
            resultTable.Columns.Add("文件名", typeof(string));
            resultTable.Columns.Add("宗地号", typeof(string));
            resultTable.Columns.Add("替换内容", typeof(string));
            resultTable.Columns.Add("原始文件名", typeof(string)); // 隐藏列,存储完整路径

            dataGridView1.DataSource = resultTable;
            dataGridView1.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.Fill;
            dataGridView1.ReadOnly = true;
            dataGridView1.CellClick += DataGridView1_CellClick;

            // 隐藏原始文件名列
            if (dataGridView1.Columns["原始文件名"] != null)
            {
                dataGridView1.Columns["原始文件名"].Visible = false;
            }
        }

        private void InitializeBackgroundWorker()
        {
            backgroundWorker = new BackgroundWorker();
            backgroundWorker.WorkerReportsProgress = true;
            backgroundWorker.WorkerSupportsCancellation = true;

            backgroundWorker.DoWork += BackgroundWorker_DoWork;
            backgroundWorker.ProgressChanged += BackgroundWorker_ProgressChanged;
            backgroundWorker.RunWorkerCompleted += BackgroundWorker_RunWorkerCompleted;
        }

        // DataGridView 单元格点击事件
        private void DataGridView1_CellClick(object sender, DataGridViewCellEventArgs e)
        {
            if (e.RowIndex < 0 || e.ColumnIndex < 0) return;

            // 只处理文件名列的点击
            if (dataGridView1.Columns[e.ColumnIndex].Name == "文件名")
            {
                // 获取原始文件路径
                string originalPath = dataGridView1.Rows[e.RowIndex].Cells["原始文件名"].Value?.ToString();

                if (!string.IsNullOrEmpty(originalPath))
                {
                    try
                    {
                        OpenWordDocument(originalPath);
                    }
                    catch (Exception ex)
                    {
                        MessageBox.Show($"打开Word文档失败:{ex.Message}", "错误",
                            MessageBoxButtons.OK, MessageBoxIcon.Error);
                    }
                }
            }
        }

        // 打开Word文档
        private void OpenWordDocument(string filePath)
        {
            if (File.Exists(filePath))
            {
                Process.Start(new ProcessStartInfo(filePath) { UseShellExecute = true });
            }
            else
            {
                MessageBox.Show($"文件不存在:{filePath}", "错误",
                    MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        // 选择目录按钮
        private void button1_Click(object sender, EventArgs e)
        {
            using (FolderBrowserDialog folderDialog = new FolderBrowserDialog())
            {
                folderDialog.Description = "选择包含Word文档的目录";

                if (folderDialog.ShowDialog() == DialogResult.OK)
                {
                    textBox1.Text = folderDialog.SelectedPath;
                    currentDirectory = folderDialog.SelectedPath;

                    // 清空之前的结果
                    resultTable.Rows.Clear();
                    dataGridView1.Refresh();

                    // 重置进度条
                    progressBar1.Value = 0;
                    progressBar1.Maximum = 100;

                    // 禁用按钮,防止重复操作
                    button1.Enabled = false;
                    button2.Enabled = false;
                    button2.Text = "正在处理...";

                    // 开始处理
                    backgroundWorker.RunWorkerAsync(folderDialog.SelectedPath);
                }
            }
        }

        // 后台工作线程
        private void BackgroundWorker_DoWork(object sender, DoWorkEventArgs e)
        {
            string directoryPath = e.Argument as string;
            if (string.IsNullOrEmpty(directoryPath))
            {
                return;
            }

            try
            {
                // 获取所有docx文件
                string[] docxFiles = Directory.GetFiles(directoryPath, "*.docx", SearchOption.AllDirectories);
                totalFiles = docxFiles.Length;
                processedFiles = 0;

                if (totalFiles == 0)
                {
                    backgroundWorker.ReportProgress(100, "目录中没有找到Word文档");
                    return;
                }

                // 处理每个文件
                foreach (string filePath in docxFiles)
                {
                    if (backgroundWorker.CancellationPending)
                    {
                        e.Cancel = true;
                        return;
                    }

                    ProcessSingleDocument(filePath, directoryPath);

                    // 更新进度
                    processedFiles++;
                    int progress = (int)((processedFiles * 100) / totalFiles);
                    backgroundWorker.ReportProgress(progress, $"正在处理: {Path.GetFileName(filePath)}");
                }

                e.Result = directoryPath;
            }
            catch (Exception ex)
            {
                e.Result = ex;
            }
        }

        // 进度更新
        private void BackgroundWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            progressBar1.Value = e.ProgressPercentage;

            if (e.UserState != null)
            {
                this.Text = $"界止签章宗地号替换 - {e.UserState}";
                labelStatus.Text = e.UserState.ToString();
            }
        }

        // 处理完成
        private void BackgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            button1.Enabled = true;
            button2.Enabled = true;
            button2.Text = "导出Excel";

            if (e.Cancelled)
            {
                MessageBox.Show("处理已取消", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
                this.Text = "界止签章宗地号替换 - 已取消";
            }
            else if (e.Error != null)
            {
                MessageBox.Show($"处理过程中出现错误:{e.Error.Message}", "错误",
                    MessageBoxButtons.OK, MessageBoxIcon.Error);
                this.Text = "界止签章宗地号替换 - 错误";
            }
            else
            {
                if (e.Result is string directoryPath)
                {
                    progressBar1.Value = 100;

                    // 处理完成后自动导出并打开Excel
                    AutoExportAndOpenExcel(directoryPath);

                    this.Text = "界止签章宗地号替换 - 完成";
                }
                else if (e.Result is Exception ex)
                {
                    MessageBox.Show($"处理过程中出现错误:{ex.Message}", "错误",
                        MessageBoxButtons.OK, MessageBoxIcon.Error);
                }
            }
        }

        // 自动导出并打开Excel
        private void AutoExportAndOpenExcel(string directoryPath)
        {
            try
            {
                if (resultTable.Rows.Count == 0)
                {
                    MessageBox.Show("没有数据可以导出!", "提示",
                        MessageBoxButtons.OK, MessageBoxIcon.Information);
                    return;
                }

                // 生成Excel文件名
                string excelFileName = $"签章明细表_{DateTime.Now:yyyyMMdd_HHmmss}.xlsx";
                string excelFilePath = Path.Combine(directoryPath, excelFileName);

                // 导出Excel
                ExportToExcel(excelFilePath);

                // 打开Excel文件
                OpenExcelFile(excelFilePath);

                MessageBox.Show($"处理完成!共处理 {totalFiles} 个文档。\nExcel文件已自动打开:{excelFilePath}",
                    "完成", MessageBoxButtons.OK, MessageBoxIcon.Information);
            }
            catch (Exception ex)
            {
                MessageBox.Show($"自动导出Excel时出错:{ex.Message}\n请手动导出。", "警告",
                    MessageBoxButtons.OK, MessageBoxIcon.Warning);
            }
        }

        // 打开Excel文件
        private void OpenExcelFile(string filePath)
        {
            try
            {
                if (File.Exists(filePath))
                {
                    Process.Start(new ProcessStartInfo(filePath) { UseShellExecute = true });
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show($"打开Excel文件时出错:{ex.Message}", "错误",
                    MessageBoxButtons.OK, MessageBoxIcon.Warning);
            }
        }

        // 处理单个文档
        private void ProcessSingleDocument(string filePath, string baseDirectory)
        {
            try
            {
                string fileName = Path.GetFileName(filePath);
                string relativePath = filePath.Substring(baseDirectory.Length + 1);

                // 从文件名中提取宗地号
                string parcelNumber = ExtractParcelNumber(fileName);

                // 检查是否需要设置眉页(根据checkBox1状态)
                bool headerAdded = false;
                if (checkBox1.Checked)
                {
                    // 1. 眉页左插入宗地号
                    headerAdded = AddHeaderWithParcelNumber(filePath, parcelNumber);
                }

                // 2. 查找并替换括号内容
                List<string> replacedContents = FindAndReplaceBracketContent(filePath);

                // 3. 添加到DataGridView(需要在UI线程中执行)
                AddToDataGridView(relativePath, parcelNumber, replacedContents, headerAdded, filePath);
            }
            catch (Exception ex)
            {
                // 记录错误但不停止处理其他文件
                AddToDataGridView(filePath, "错误", new List<string> { $"处理失败: {ex.Message}" }, false, filePath);
            }
        }

        // 从文件名提取宗地号(修改版本:取最后7位)
        private string ExtractParcelNumber(string fileName)
        {
            try
            {
                // 移除扩展名
                string nameWithoutExt = Path.GetFileNameWithoutExtension(fileName);

                // 移除"-界址签章表"等后缀
                if (nameWithoutExt.Contains("-界址签章表"))
                {
                    nameWithoutExt = nameWithoutExt.Replace("-界址签章表", "");
                }
                else if (nameWithoutExt.Contains("-界址签..."))
                {
                    nameWithoutExt = nameWithoutExt.Replace("-界址签...", "");
                }
                else if (nameWithoutExt.Contains("-界址签"))
                {
                    nameWithoutExt = nameWithoutExt.Replace("-界址签", "");
                }
                else if (nameWithoutExt.Contains("-界址"))
                {
                    nameWithoutExt = nameWithoutExt.Replace("-界址", "");
                }
                else if (nameWithoutExt.Contains("-"))
                {
                    nameWithoutExt = nameWithoutExt.Split('-')[0];
                }

                // 提取完整宗地号(如:110113113001JC14800 或 110113113001JB50553)
                // 正则表达式匹配:数字开头 + JC/JB + 数字
                Match match = Regex.Match(nameWithoutExt, @"\d{6,}(JC|JB)\d+");
                if (match.Success)
                {
                    // 取最后7位
                    string fullNumber = match.Value;
                    if (fullNumber.Length >= 7)
                    {
                        return fullNumber.Substring(fullNumber.Length - 7);
                    }
                    return fullNumber;
                }

                // 如果上面的正则不匹配,尝试更通用的模式
                match = Regex.Match(nameWithoutExt, @"\d{12,}");
                if (match.Success)
                {
                    string fullNumber = match.Value;
                    if (fullNumber.Length >= 7)
                    {
                        return fullNumber.Substring(fullNumber.Length - 7);
                    }
                    return fullNumber;
                }

                // 如果还是找不到,返回整个文件名(不含扩展名)的最后7位
                if (nameWithoutExt.Length >= 7)
                {
                    return nameWithoutExt.Substring(nameWithoutExt.Length - 7);
                }
                return nameWithoutExt;
            }
            catch
            {
                // 如果出错,返回最后7位
                string nameWithoutExt = Path.GetFileNameWithoutExtension(fileName);
                if (nameWithoutExt.Length >= 7)
                {
                    return nameWithoutExt.Substring(nameWithoutExt.Length - 7);
                }
                return nameWithoutExt;
            }
        }

        // 眉页左插入宗地号 - 修复版本
        private bool AddHeaderWithParcelNumber(string filePath, string parcelNumber)
        {
            try
            {
                // 备份原文件
                string backupPath = filePath + ".backup";
                File.Copy(filePath, backupPath, true);

                try
                {
                    using (WordprocessingDocument doc = WordprocessingDocument.Open(filePath, true))
                    {
                        // 获取主文档部分
                        MainDocumentPart mainPart = doc.MainDocumentPart;

                        // 检查是否已有页眉部分
                        HeaderPart headerPart = mainPart.HeaderParts.FirstOrDefault();

                        if (headerPart == null)
                        {
                            // 创建新的页眉部分
                            headerPart = mainPart.AddNewPart<HeaderPart>();

                            // 获取页眉的ID
                            string headerPartId = mainPart.GetIdOfPart(headerPart);

                            // 获取或创建SectionProperties
                            var sectionProps = mainPart.Document.Body.Descendants<SectionProperties>().FirstOrDefault();
                            if (sectionProps == null)
                            {
                                sectionProps = new SectionProperties();
                                mainPart.Document.Body.Append(sectionProps);
                            }

                            // 添加页眉引用
                            sectionProps.PrependChild(new HeaderReference
                            {
                                Id = headerPartId,
                                Type = HeaderFooterValues.Default
                            });
                        }

                        // 确保Header不为null
                        if (headerPart.Header == null)
                        {
                            headerPart.Header = new Header();
                        }
                        else
                        {
                            // 清空现有内容
                            headerPart.Header.RemoveAllChildren();
                        }

                        // 创建段落
                        Paragraph paragraph = new Paragraph();

                        // 设置段落属性
                        ParagraphProperties paragraphProperties = new ParagraphProperties();

                        // 设置对齐方式
                        paragraphProperties.Append(new Justification()
                        {
                            Val = JustificationValues.Left
                        });

                        // 设置段落间距
                        paragraphProperties.Append(new SpacingBetweenLines()
                        {
                            After = "0",
                            Line = "240",
                            LineRule = LineSpacingRuleValues.Auto
                        });

                        paragraph.AppendChild(paragraphProperties);

                        // 创建文本运行
                        Run run = new Run();

                        // 设置运行属性(字体、大小、颜色)
                        RunProperties runProperties = new RunProperties();

                        // 设置字体:宋体
                        runProperties.Append(new RunFonts()
                        {
                            Ascii = "宋体",
                            HighAnsi = "宋体",
                            EastAsia = "宋体"
                        });

                        // 设置字体大小:5号字体(约10.5磅 = 21半磅)
                        runProperties.Append(new WordFontSize()
                        {
                            Val = "21"  // 半磅单位
                        });

                        // 设置字体颜色:灰色
                        runProperties.Append(new WordColor()
                        {
                            Val = "808080"  // RGB: 80,80,80
                        });

                        run.RunProperties = runProperties;

                        // 添加文本
                        run.AppendChild(new Text(parcelNumber));

                        // 将运行添加到段落
                        paragraph.AppendChild(run);

                        // 将段落添加到页眉
                        headerPart.Header.AppendChild(paragraph);

                        // 保存更改
                        doc.Save();

                        // 删除备份文件
                        if (File.Exists(backupPath))
                        {
                            File.Delete(backupPath);
                        }

                        return true;
                    }
                }
                catch (Exception)
                {
                    // 如果出错,恢复备份
                    if (File.Exists(backupPath))
                    {
                        File.Copy(backupPath, filePath, true);
                        File.Delete(backupPath);
                    }
                    throw;
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine($"添加页眉时出错:{ex.Message}");
                // 记录详细错误信息
                Debug.WriteLine($"详细错误信息: {ex.ToString()}");
                return false;
            }
        }

        // 查找并替换括号内容
        private List<string> FindAndReplaceBracketContent(string filePath)
        {
            List<string> replacedContents = new List<string>();

            try
            {
                // 备份原文件
                string backupPath = filePath + ".replace_backup";
                File.Copy(filePath, backupPath, true);

                try
                {
                    using (WordprocessingDocument doc = WordprocessingDocument.Open(filePath, true))
                    {
                        Body body = doc.MainDocumentPart.Document.Body;

                        // 查找所有文本元素
                        var textElements = body.Descendants<Text>().ToList();

                        foreach (var textElement in textElements)
                        {
                            string originalText = textElement.Text;

                            if (string.IsNullOrEmpty(originalText))
                                continue;

                            // 使用正则表达式查找括号内容
                            string pattern = @"\(([^)]+)\)";
                            MatchCollection matches = Regex.Matches(originalText, pattern);

                            if (matches.Count > 0)
                            {
                                string newText = originalText;

                                foreach (Match match in matches)
                                {
                                    string bracketContent = match.Groups[1].Value;

                                    // 添加到替换内容列表
                                    if (!replacedContents.Contains(bracketContent))
                                    {
                                        replacedContents.Add(bracketContent);
                                    }

                                    // 替换为空字符串
                                    newText = newText.Replace(match.Value, "");
                                }

                                // 更新文本元素
                                textElement.Text = newText;
                            }
                        }

                        // 保存文档
                        doc.MainDocumentPart.Document.Save();

                        // 删除备份文件
                        if (File.Exists(backupPath))
                        {
                            File.Delete(backupPath);
                        }
                    }
                }
                catch (Exception)
                {
                    // 如果出错,恢复备份
                    if (File.Exists(backupPath))
                    {
                        File.Copy(backupPath, filePath, true);
                        File.Delete(backupPath);
                    }
                    throw;
                }
            }
            catch (Exception ex)
            {
                replacedContents.Add($"处理括号时出错: {ex.Message}");
            }

            return replacedContents;
        }

        // 添加到DataGridView(线程安全)
        private void AddToDataGridView(string fileName, string parcelNumber, List<string> replacedContents, bool headerAdded, string fullPath)
        {
            if (this.InvokeRequired)
            {
                this.Invoke(new Action(() =>
                    AddToDataGridView(fileName, parcelNumber, replacedContents, headerAdded, fullPath)));
                return;
            }

            string displayFileName = fileName.Length > 30 ? fileName.Substring(0, 30) + "..." : fileName;

            if (replacedContents.Count == 0)
            {
                DataRow row = resultTable.NewRow();
                row["文件名"] = displayFileName;
                row["宗地号"] = parcelNumber;
                row["替换内容"] = headerAdded ? "已添加页眉(无括号内容)" : "无括号内容";
                row["原始文件名"] = fullPath;
                resultTable.Rows.Add(row);
            }
            else
            {
                foreach (string content in replacedContents)
                {
                    DataRow row = resultTable.NewRow();
                    row["文件名"] = displayFileName;
                    row["宗地号"] = parcelNumber;
                    row["替换内容"] = content;
                    row["原始文件名"] = fullPath;
                    resultTable.Rows.Add(row);
                }
            }

            // 自动刷新显示
            dataGridView1.Refresh();
        }

        // 导出Excel按钮(手动导出)
        private void button2_Click(object sender, EventArgs e)
        {
            if (resultTable.Rows.Count == 0)
            {
                MessageBox.Show("没有数据可以导出!", "提示",
                    MessageBoxButtons.OK, MessageBoxIcon.Information);
                return;
            }

            using (SaveFileDialog saveDialog = new SaveFileDialog())
            {
                saveDialog.Filter = "Excel文件 (*.xlsx)|*.xlsx";
                saveDialog.FileName = $"签章明细表_{DateTime.Now:yyyyMMdd_HHmmss}.xlsx";
                saveDialog.DefaultExt = "xlsx";
                saveDialog.InitialDirectory = currentDirectory ?? textBox1.Text;

                if (saveDialog.ShowDialog() == DialogResult.OK)
                {
                    try
                    {
                        ExportToExcel(saveDialog.FileName);

                        // 询问是否打开文件
                        if (MessageBox.Show($"导出成功!是否打开Excel文件?",
                            "导出成功", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)
                        {
                            OpenExcelFile(saveDialog.FileName);
                        }
                    }
                    catch (Exception ex)
                    {
                        MessageBox.Show($"导出Excel时出错:{ex.Message}", "错误",
                            MessageBoxButtons.OK, MessageBoxIcon.Error);
                    }
                }
            }
        }

        // 导出到Excel
        private void ExportToExcel(string filePath)
        {
            // 设置EPPlus的LicenseContext
            ExcelPackage.LicenseContext = OfficeOpenXml.LicenseContext.NonCommercial;

            using (ExcelPackage excelPackage = new ExcelPackage())
            {
                // 创建工作表
                ExcelWorksheet worksheet = excelPackage.Workbook.Worksheets.Add("签章明细");

                // 设置列标题
                worksheet.Cells[1, 1].Value = "文件名";
                worksheet.Cells[1, 2].Value = "宗地号";
                worksheet.Cells[1, 3].Value = "替换内容";

                // 设置标题样式
                using (var headerRange = worksheet.Cells[1, 1, 1, 3])
                {
                    headerRange.Style.Font.Bold = true;
                    headerRange.Style.Fill.PatternType = Excel.Style.ExcelFillStyle.Solid;
                    headerRange.Style.Fill.BackgroundColor.SetColor(System.Drawing.Color.LightBlue);
                    headerRange.Style.HorizontalAlignment = Excel.Style.ExcelHorizontalAlignment.Center;
                    headerRange.Style.Border.Bottom.Style = Excel.Style.ExcelBorderStyle.Thin;
                }

                // 填充数据
                for (int i = 0; i < resultTable.Rows.Count; i++)
                {
                    worksheet.Cells[i + 2, 1].Value = resultTable.Rows[i]["文件名"].ToString();
                    worksheet.Cells[i + 2, 2].Value = resultTable.Rows[i]["宗地号"].ToString();
                    worksheet.Cells[i + 2, 3].Value = resultTable.Rows[i]["替换内容"].ToString();
                }

                // 设置列宽
                worksheet.Column(1).Width = 40; // 文件名列
                worksheet.Column(2).Width = 15; // 宗地号列
                worksheet.Column(3).Width = 40; // 替换内容列

                // 添加边框
                using (var dataRange = worksheet.Cells[1, 1, resultTable.Rows.Count + 1, 3])
                {
                    dataRange.Style.Border.Top.Style = Excel.Style.ExcelBorderStyle.Thin;
                    dataRange.Style.Border.Bottom.Style = Excel.Style.ExcelBorderStyle.Thin;
                    dataRange.Style.Border.Left.Style = Excel.Style.ExcelBorderStyle.Thin;
                    dataRange.Style.Border.Right.Style = Excel.Style.ExcelBorderStyle.Thin;
                }

                // 添加统计信息
                int lastRow = resultTable.Rows.Count + 4;
                worksheet.Cells[lastRow, 1].Value = "统计信息:";
                worksheet.Cells[lastRow, 1].Style.Font.Bold = true;
                worksheet.Cells[lastRow + 1, 1].Value = "处理文件总数:";
                worksheet.Cells[lastRow + 1, 2].Value = totalFiles;
                worksheet.Cells[lastRow + 2, 1].Value = "设置眉页:";
                worksheet.Cells[lastRow + 2, 2].Value = checkBox1.Checked ? "是" : "否";
                worksheet.Cells[lastRow + 3, 1].Value = "处理时间:";
                worksheet.Cells[lastRow + 3, 2].Value = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");

                // 保存文件
                excelPackage.SaveAs(new FileInfo(filePath));
            }
        }

        // 窗体关闭时
        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (backgroundWorker.IsBusy)
            {
                if (MessageBox.Show("正在处理文件,确定要退出吗?", "确认退出",
                    MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.No)
                {
                    e.Cancel = true;
                }
                else
                {
                    backgroundWorker.CancelAsync();
                }
            }
        }
    }
}

Form1.Designer.cs

csharp 复制代码
namespace _14界止签章宗地号替换
{
    partial class Form1
    {
        /// <summary>
        ///  Required designer variable.
        /// </summary>
        private System.ComponentModel.IContainer components = null;

        /// <summary>
        ///  Clean up any resources being used.
        /// </summary>
        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null))
            {
                components.Dispose();
            }
            base.Dispose(disposing);
        }

        #region Windows Form Designer generated code

        /// <summary>
        ///  Required method for Designer support - do not modify
        ///  the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        {
            button1 = new Button();
            button2 = new Button();
            textBox1 = new TextBox();
            progressBar1 = new ProgressBar();
            dataGridView1 = new DataGridView();
            labelStatus = new Label();
            checkBox1 = new CheckBox();
            ((System.ComponentModel.ISupportInitialize)dataGridView1).BeginInit();
            SuspendLayout();
            // 
            // button1
            // 
            button1.Location = new Point(547, 8);
            button1.Name = "button1";
            button1.Size = new Size(100, 27);
            button1.TabIndex = 0;
            button1.Text = "选择目录";
            button1.UseVisualStyleBackColor = true;
            button1.Click += button1_Click;
            // 
            // button2
            // 
            button2.Location = new Point(547, 41);
            button2.Name = "button2";
            button2.Size = new Size(100, 25);
            button2.TabIndex = 4;
            button2.Text = "导出Excel";
            button2.UseVisualStyleBackColor = true;
            button2.Click += button2_Click;
            // 
            // textBox1
            // 
            textBox1.Location = new Point(12, 12);
            textBox1.Name = "textBox1";
            textBox1.Size = new Size(529, 23);
            textBox1.TabIndex = 1;
            // 
            // progressBar1
            // 
            progressBar1.Location = new Point(12, 42);
            progressBar1.Name = "progressBar1";
            progressBar1.Size = new Size(529, 23);
            progressBar1.TabIndex = 2;
            // 
            // dataGridView1
            // 
            dataGridView1.ColumnHeadersHeightSizeMode = DataGridViewColumnHeadersHeightSizeMode.AutoSize;
            dataGridView1.Location = new Point(12, 91);
            dataGridView1.Name = "dataGridView1";
            dataGridView1.Size = new Size(635, 354);
            dataGridView1.TabIndex = 3;
            // 
            // labelStatus
            // 
            labelStatus.AutoSize = true;
            labelStatus.Location = new Point(11, 69);
            labelStatus.Name = "labelStatus";
            labelStatus.Size = new Size(43, 17);
            labelStatus.TabIndex = 5;
            labelStatus.Text = "label1";
            // 
            // checkBox1
            // 
            checkBox1.AutoSize = true;
            checkBox1.Location = new Point(512, 68);
            checkBox1.Name = "checkBox1";
            checkBox1.Size = new Size(89, 21);
            checkBox1.TabIndex = 6;
            checkBox1.Text = "checkBox1";
            checkBox1.UseVisualStyleBackColor = true;
            // 
            // Form1
            // 
            AutoScaleDimensions = new SizeF(7F, 17F);
            AutoScaleMode = AutoScaleMode.Font;
            ClientSize = new Size(659, 450);
            Controls.Add(checkBox1);
            Controls.Add(labelStatus);
            Controls.Add(dataGridView1);
            Controls.Add(button2);
            Controls.Add(progressBar1);
            Controls.Add(textBox1);
            Controls.Add(button1);
            Name = "Form1";
            Text = "界止签章宗地号替换";
            ((System.ComponentModel.ISupportInitialize)dataGridView1).EndInit();
            ResumeLayout(false);
            PerformLayout();
        }

        #endregion

        private System.Windows.Forms.Button button1;
        private System.Windows.Forms.Button button2;
        private System.Windows.Forms.TextBox textBox1;
        private ProgressBar progressBar1;
        private DataGridView dataGridView1;
        private Label labelStatus;
        private CheckBox checkBox1;
    }
}
相关推荐
qq_4252633220 小时前
.net开发框架和语言
c#
武藤一雄21 小时前
C# 关于多线程如何实现需要注意的问题(持续更新)
windows·后端·microsoft·c#·.net·.netcore·死锁
flysh0521 小时前
C# 架构设计:接口 vs 抽象类的深度选型指南
开发语言·c#
flysh051 天前
C# 中类型转换与模式匹配核心概念
开发语言·c#
故事不长丨1 天前
C#字典(Dictionary)全面解析:从基础用法到实战优化
开发语言·c#·wpf·哈希算法·字典·dictionary·键值对
wtsolutions1 天前
Sheet-to-Doc占位符系统详解:让数据自动填入Word指定位置
开发语言·c#
kylezhao20191 天前
C#上位机多语言切换实现
c#·工控上位机
我是唐青枫1 天前
深入理解 System.Lazy<T>:C#.NET 延迟初始化与线程安全
c#·.net
zxy28472253011 天前
利用C#对接BotSharp本地大模型AI Agent示例(2)
人工智能·c#·api·ai agent·botsharp