在现代软件开发中,处理PDF文件的需求日益增长。最近,接到了一个客户的请求,他们希望创建一个应用程序,允许用户填写PDF表单,并将数据存储到数据库中。
在寻找解决方案的过程中,发现了许多处理PDF文件的库。这些库大多数都强调了在代码中创建PDF文档的便捷性,许多库提供了读取文档的能力,但几乎所有的库都无法加载使用Adobe Acrobat创建的文档,它们只能打开较旧的未加密PDF文件。
找到的一个例外是iTextSharp,这是一个来自的库,它提供了商业版本和开源版本,开源版本带有AGPL许可证。
下载代码后,需要使用Nuget下载iTextSharp和SQLite包。请注意每个包的许可要求。
该项目是在Visual Studio 2015上开发的,目标是.NET版本4.5,但也在Visual Studio 2013上进行了测试。
包含的软件是为客户工作的解决方案。它是一个Windows服务,用于监视被放置或修改到特定位置的PDF文件,读取表单字段集合和页面内容标记。
表单字段集合作为键值对保存在SQLite数据库表中,字段名称作为键,其数据作为值。
项目由四个项目和一个部署项目组成,以帮助安装:
以下是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获取包。