三公机器人

牛牛机器人,三公撑船机器人,微信牛牛机器人

牛牛机器人 使用 iText 7(推荐,适合 .NET Core/.NET 6+)

在 C# 中获取 PDF 表单(AcroForm)中已填写的内容,主要依赖于第三方 PDF 处理库。目前

主流且推荐的方案是使用 ‌iText 7‌ 或 ‌Spire.PDF‌。以下是基于不同库的具体实现方法及关键注意事项。


方案一:使用 iText 7(推荐,适合 .NET Core/.NET 6+)


iText 7 是目前功能最强大且维护活跃的库,能够很好地处理中文、复杂表单结构及签名域。


1. 安装 NuGet 包

bash

Install-Package itext7

Install-Package itext7.pdfa


2. 核心代码实现


以下代码展示了如何遍历所有表单域并提取其名称和值:


csharp

using iText.Kernel.Pdf;

using iText.Forms;

using iText.Forms.Fields;

using System;

using System.Collections.Generic;


public class PdfFormExtractor

{

    public static Dictionary<string, string> ExtractFormData(string pdfPath)

    {

        var formData = new Dictionary<string, string>();

        

        // 使用 PdfReader 加载文件,确保元数据完整

        using (PdfReader reader = new PdfReader(pdfPath))

        using (PdfDocument pdfDoc = new PdfDocument(reader))

        {

            // 获取 AcroForm 对象

            PdfAcroForm acroForm = PdfAcroForm.GetAcroForm(pdfDoc, false);

            

            if (acroForm != null)

            {

                // 获取所有字段名称

                IList<string> fieldNames = acroForm.GetFieldNames();

                

                foreach (string fieldName in fieldNames)

                {

                    PdfFormField field = acroForm.GetField(fieldName);

                    

                    // 跳过签名域,避免干扰或错误

                    if (field.GetFieldType().Equals(PdfName.SIG))

                        continue;


                    // 获取字段值

                    string value = field.GetValueAsString();

                    

                    // 存入字典,key为字段名,value为填写内容

                    formData[fieldName] = value ?? string.Empty;

                }

            }

            

            // 重要:必须调用 Close 以确保资源释放和数据完整性

            pdfDoc.Close();

        }

        

        return formData;

    }

}


3. 关键注意事项

中文字体问题‌:如果提取到的中文显示为乱码或空块,通常是因为 PDF 内部字体嵌入问题。但在‌读取‌场景下,

GetValueAsString() 通常能正确返回 Unicode 字符串。如果遇到显示问题,需检查 PDF 阅读器端的字体支持,

而非代码提取逻辑。

字段名区分大小写‌:PDF 表单字段名是严格区分大小写的,且可能包含复杂的前缀(如 form1.TextField1)。

建议先打印所有 fieldNames 以确认确切名称。

关闭文档‌:务必调用 pdfDoc.Close() 而不是仅依赖 Dispose,以确保底层流正确刷新。

方案二:使用 Spire.PDF for .NET(易用性高)


Spire.PDF 提供了更面向对象的 API,适合快速开发,尤其是对不同类型的表单控件(文本框、复选框等)有专门的类支持。


1. 安装 NuGet 包

bash

Install-Package Spire.PDF


2. 核心代码实现

csharp

using Spire.Pdf;

using Spire.Pdf.Fields;

using Spire.Pdf.Widget;

using System.Collections.Generic;


public class SpirePdfExtractor

{

    public static List<Dictionary<string, string>> ExtractFormData(string pdfPath)

    {

        var result = new List<Dictionary<string, string>>();

        

        // 加载 PDF 文档

        using (PdfDocument doc = new PdfDocument())

        {

            doc.LoadFromFile(pdfPath);

            

            // 获取表单对象

            PdfFormWidget formWidget = doc.Form as PdfFormWidget;

            

            if (formWidget != null && formWidget.FieldsWidget.List.Count > 0)

            {

                foreach (PdfField field in formWidget.FieldsWidget.List)

                {

                    var fieldData = new Dictionary<string, string>();

                    string fieldName = field.Name;

                    string fieldValue = string.Empty;


                    // 根据字段类型提取值

                    if (field is PdfTextBoxFieldWidget textBox)

                    {

                        fieldValue = textBox.Text;

                    }

                    else if (field is PdfCheckBoxFieldWidget checkBox)

                    {

                        fieldValue = checkBox.Checked ? "True" : "False";

                    }

                    else if (field is PdfRadioButtonListFieldWidget radio)

                    {

                        fieldValue = radio.SelectedValue;

                    }

                    else if (field is PdfComboBoxFieldWidget comboBox)

                    {

                        fieldValue = comboBox.SelectedValue;

                    }

                    else if (field is PdfListBoxFieldWidget listBox)

                    {

                        fieldValue = listBox.SelectedValue;

                    }


                    fieldData["Name"] = fieldName;

                    fieldData["Value"] = fieldValue;

                    result.Add(fieldData);

                }

            }

        }

        

        return result;

    }

}


方案三:使用 iTextSharp 5(仅限旧项目维护)


警告‌:iTextSharp 5 已停止维护,不支持 .NET Core/.NET 6+,且存在已知漏洞。仅建议在遗留的 .NET Framework 项目中暂时使用。


csharp

using iTextSharp.text.pdf;

using System.Collections.Generic;


public class LegacyPdfExtractor

{

    public static Dictionary<string, string> ExtractFormData(string pdfPath)

    {

        var formData = new Dictionary<string, string>();

        

        using (PdfReader reader = new PdfReader(pdfPath))

        {

            // 获取 AcroFields

            AcroFields fields = reader.AcroFields;

            

            // 获取所有字段名

            foreach (string fieldName in fields.Fields.Keys)

            {

                // 获取字段值

                string value = fields.GetField(fieldName);

                formData[fieldName] = value;

            }

        }

        

        return formData;

    }

}


常见问题与最佳实践


如何处理 XFA 表单?‌


上述方法主要针对标准的 ‌AcroForm‌。如果 PDF 使用的是动态 XFA 表单(常见于 Adobe LiveCycle 生成的表单),

iText 7 支持有限,可能需要使用 XfaForm 类进行 XML 解析。Spire.PDF 对 XFA 的支持也相对有限。对于复杂 XFA,

建议先转换为标准 AcroForm 或使用 Adobe SDK。


字段值为空怎么办?‌


检查字段是否被设置为“只读”。

确认字段名是否正确(使用调试器打印所有字段名)。

某些字段可能没有默认值,用户未填写时即为空字符串。


性能优化‌


如果需要批量处理大量 PDF,建议复用 PdfReader 实例(线程安全需注意)或使用并行处理(Parallel.ForEach),但需确保每个线程独立加载文档。


安全性‌


如果 PDF 包含数字签名,提取数据时不要修改文档结构,否则会导致签名失效。上述读取操作均为只读,不会影响签名。


选择哪种方案取决于你的项目环境:


.NET Core / .NET 6+ 新项目‌:首选 ‌iText 7‌。

需要简单 API 且预算允许‌:选择 ‌Spire.PDF‌。

旧版 .NET Framework 项目‌:可继续使用 ‌iTextSharp 5‌,但建议逐步迁移。


Powered By Z-BlogPHP 1.7.3

三公机器人,牛牛机器人,三公撑船机器人,微信牛牛机器人