PDF文件处理与数据库存储解决方案

在现代软件开发中,处理PDF文件的需求日益增长。最近,接到了一个客户的请求,他们希望创建一个应用程序,允许用户填写PDF表单,并将数据存储到数据库中。

在寻找解决方案的过程中,发现了许多处理PDF文件的库。这些库大多数都强调了在代码中创建PDF文档的便捷性,许多库提供了读取文档的能力,但几乎所有的库都无法加载使用Adobe Acrobat创建的文档,它们只能打开较旧的未加密PDF文件。

找到的一个例外是iTextSharp,这是一个来自的库,它提供了商业版本和开源版本,开源版本带有AGPL许可证。

使用代码

下载代码后,需要使用Nuget下载iTextSharp和SQLite包。请注意每个包的许可要求。

该项目是在Visual Studio 2015上开发的,目标是.NET版本4.5,但也在Visual Studio 2013上进行了测试。

包含的软件是为客户工作的解决方案。它是一个Windows服务,用于监视被放置或修改到特定位置的PDF文件,读取表单字段集合和页面内容标记。

表单字段集合作为键值对保存在SQLite数据库表中,字段名称作为键,其数据作为值。

项目由四个项目和一个部署项目组成,以帮助安装:

  • SaveToDB - 包含程序运行器,用于查找要放置并保存到数据库的文件。
  • DataClass - 提供读取和写入数据库的方法,支持SQLite调用以及Microsoft SQL Server。使用providerName="SQLite"在连接字符串中保存到SQLite数据库,否则默认为SQL Server。
  • LoggerClass - 简化的日志记录程序。
  • PDFScanner - 一个Windows服务项目,引导程序运行器并包含installutil.exe的安装程序。

以下是C#代码的一个示例,展示了如何配置和使用这些类:

NameValueCollection cfg = ConfigurationManager.AppSettings; ProgramRunner pr = new ProgramRunner(); ILogger lg = new Logger((Logger.LogLevel)Enum.Parse(typeof(Logger.LogLevel), cfg["LogLevel"]), cfg["LogLocation"], "logDB.txt"); pr.runProgram(lg, cfg);

主处理过程被封装在一个using语句中,并且为每个被放置或更改的文件夹中的文件进行处理。PdfReader有十二种不同的重载,选择的是直接从磁盘打开文件的重载。using语句确保与PdfReader相关的所有资源都被正确关闭和释放。

foreach (string item in GetFilesToProcess()) { string newFile = RenameFile(item); using (PdfReader reader = new PdfReader(item)) { // ... } }

在读取PDF文件时,会扫描文本和表单字段。以下代码段读取第一页,返回一个StringBuilder对象,该对象可以与数据库中保存的表单类型进行正则表达式匹配。

StringBuilder sb = new StringBuilder(); byte[] streamBytes = reader.GetPageContent(1); PRTokeniser tokenizer = new PRTokeniser(new RandomAccessFileOrArray(new RandomAccessSourceFactory().CreateSource(streamBytes))); while (tokenizer.NextToken()) { if (tokenizer.TokenType == PRTokeniser.TokType.STRING) { sb.Append(tokenizer.StringValue); } }

有一个选项是使用正则表达式扫描文本,寻找匹配项以确定表单类型。如果没有匹配项,它将查看文件名以确定类型,并使用文件名作为类型。

Regex rx = new Regex("Number:(?.+)Rev:"); Regex rx = new Regex(cfg["FileTypeRegEx"]); var group = rx.Match(sb.ToString()).Groups["one"]; string ftype = group.Value.ToString().Trim(); if (string.IsNullOrEmpty(ftype)) ftype = System.IO.Path.GetFileNameWithoutExtension(item);

从文档中读取AcroFields,并使用参数化查询将其保存到数据库中。AcroFields是整个文档的,而不是按页面引用的。

foreach (var field in fields.Fields) { string fvalue = fields.GetField(field.Key.ToString()).ToString(); if (!string.IsNullOrEmpty(fvalue.Trim())) { _locallog.Log("insert data", "storage", Logger.LogLevel.Info); while (!dbstuff.execCmdsNonQuery(sqldb, "insert into tstorage (FileName,FieldName,FieldValue,FieldType,FileType) values (@file,@field,@value,@type,@filetype)", new SqlParameter[] {...})) { // ... } } }

数据库表使用以下模式定义:

CREATE TABLE "TStorage" ( `FileName` TEXT NOT NULL, `FieldName` TEXT NOT NULL, `FieldValue` TEXT NOT NULL, `FieldType` TEXT NOT NULL, `FieldProcessed` INTEGER DEFAULT 0, `FileType` TEXT, PRIMARY KEY (FileName,FieldName) )

有趣的点

使用iTextSharp非常简单,它有大量的有用文章和示例,并且第一次就按预期工作。这个努力非常成功,希望这能为如何使用这个优秀包的有用示例库增加内容,并希望它能帮助努力。

这个示例软件在左AGPL许可证下使用iTextSharp,已经包含了必要的通知、修改和AGPL许可证文件以及获取源代码的位置。

需要使用NuGet获取包。

  • 在知识产权(IP)或专利侵权的情况下提供赔偿。
  • 免除copyleft AGPL许可证的要求,包括:
  • 免除不更改生成的PDF属性中的PDF生产者行的要求。
  • 只有商业许可持有者才能访问商业iText支持。
沪ICP备2024098111号-1
上海秋旦网络科技中心:上海市奉贤区金大公路8218号1幢 联系电话:17898875485