我有一个windows服务,它可以动态地将PDF合并在一起,然后将它们移动到另一个位置。在大多数情况下,我无法控制某人想要合并什么。有时会处理损坏的PDF,因此创建新的PdfDocument会抛出PDFEException“Traile not found”。我捕获了异常并关闭了文档,但在关闭PDF之后,它仍然以某种方式被锁定。我需要删除该目录,但在尝试这样做时,它会引发IOException并使服务崩溃。
我已经验证了调用PdfDocument构造函数是锁定pdf的方法,并且在关闭文件后立即保持锁定状态。
有什么想法吗?iText是否可以帮助解决Is问题,或者我是否需要在检查损坏的PDF之前做一些工作?
进程目录
private void ProcessDirectory(string directoryPath)
{
EventLogManager.WriteInformation("ProcessDirectory");
// DON'T TOUCH THE BACKUPS, ERRORS AND WORK DIRECTORIES. Just in case they were made or renamed after the fact for some reason
if (directoryPath != this._errorsPath && directoryPath != this._backupsPath && directoryPath != this._workPath)
{
string pdfJsonPath = System.IO.Path.Combine(directoryPath, "pdf.json");
if (File.Exists(pdfJsonPath))
{
string workPath = System.IO.Path.Combine(this._workPath, System.IO.Path.GetFileName(directoryPath));
try
{
CopyToDirectory(directoryPath, workPath);
PdfMerge pdfMerge = null;
string jsonPath = System.IO.Path.Combine(workPath, "pdf.json");
using (StreamReader r = Helpers.GetStreamReader(jsonPath))
{
string json = r.ReadToEnd();
pdfMerge = JsonConvert.DeserializeObject<PdfMerge>(json);
}
FillFormFields(workPath, pdfMerge);
if (pdfMerge.Pdfs.Any(p => !String.IsNullOrWhiteSpace(p.OverlayFilename)))
{
ApplyOverlays(workPath, pdfMerge);
}
MergePdfs(workPath, pdfMerge);
//NumberPages(workPath, pdfMerge);
FinishPdf(workPath, pdfMerge);
// Move original to backups directory
if (DoSaveBackups)
{
string backupsPath = System.IO.Path.Combine(this._backupsPath, String.Format("{0}_{1}", System.IO.Path.GetFileName(directoryPath), DateTime.Now.ToString("yyyyMMddHHmmss")));
Directory.Move(directoryPath, backupsPath);
}
else
{
Directory.Delete(directoryPath, true);
}
}
catch (Exception ex)
{
EventLogManager.WriteError(ex);
if (DoSaveErrors)
{
// Move original to errors directory
string errorsPath = System.IO.Path.Combine(this._errorsPath, String.Format("{0}_{1}", System.IO.Path.GetFileName(directoryPath), DateTime.Now.ToString("yyyyMMddHHmmss")));
Directory.Move(directoryPath, errorsPath);
}
else
{
Directory.Delete(directoryPath, true);
}
}
// Delete work directory
// THIS IS WHERE THE IOEXCEPTION OCCURS AND THE SERVICE CRASHES
Directory.Delete(workPath, true);
}
else
{
EventLogManager.WriteInformation(String.Format("No pdf.json file. {0} skipped.", directoryPath));
}
}
}
FillFormFields
private void FillFormFields(string directoryPath, PdfMerge pdfMerge)
{
if (pdfMerge != null && pdfMerge.Pdfs != null)
{
string formPath = String.Empty;
string newFilePath;
PdfDocument document = null;
PdfAcroForm form;
PdfFormField pdfFormField;
foreach (var pdf in pdfMerge.Pdfs)
{
try
{
formPath = System.IO.Path.Combine(directoryPath, pdf.Filename);
newFilePath = System.IO.Path.Combine(
directoryPath,
String.Format("{0}{1}", String.Format("{0}{1}", System.IO.Path.GetFileNameWithoutExtension(pdf.Filename), "_Revised"), System.IO.Path.GetExtension(pdf.Filename)));
// THIS IS WHERE THE PDFEXCEPTOIN OCCURS
document = new PdfDocument(Helpers.GetPdfReader(formPath), new PdfWriter(newFilePath));
form = PdfAcroForm.GetAcroForm(document, true);
if (pdf.Fields != null && pdf.Fields.Count > 0)
{
foreach (var field in pdf.Fields)
{
if (field.Value != null)
{
pdfFormField = form.GetField(field.Name);
if (pdfFormField != null)
{
form.GetField(field.Name).SetValue(field.Value);
}
else
{
EventLogManager.WriteWarning(String.Format("Field '{0}' does not exist in '{1}'", field.Name, pdf.Filename));
}
}
}
}
form.FlattenFields();
}
catch (Exception ex)
{
throw new Exception(String.Format("An exception occurred filling form fields for {0}", pdf.Filename), ex);
}
finally
{
if (document != null)
{
document.Close();
}
}
// Now rename the new one back to the old name
File.Delete(formPath);
File.Move(newFilePath, formPath);
}
}
}
似乎为了正确地处理所有内容,您必须将单独的PdfReader和PdfWriter对象声明为using语句,并将它们传递到PdfDocument中。这样地:
using (reader = Helpers.GetPdfReader(formPath))
{
using (writer = new PdfWriter(newFilePath))
{
using (document = new PdfDocument(reader, writer))
{
// The rest of the code here
}
}
}
我不确定为什么这是除了iText没有处置个人PdfReader和PdfWriter时,处置Pdf文档,我假设它会。
我知道这是一个老问题,但这是我在iText7中解决的方法,与公认的答案大不相同。因为我不能使用using语句,所以在结束文档时采用了不同的方法。这似乎有些过分,但效果很好。
首先,我关闭了文档:
Document.Close();
这里没有什么不同寻常的。。但是,执行此操作后,我关闭/处置读写器实例。关闭它们之后,我将按顺序将writer、reader和document设置为null。GC应该负责清除这些,但是对于我的使用,保存这些实例的对象仍然在使用中,所以为了释放一些内存,我正在执行这个额外的步骤。
步骤二
Writer.Close();
Writer.Dispose();
Writer = null;
步骤3
Reader.SetCloseStream(true);
Reader.Close();
Reader = null;
步骤4
Document = null;
我建议您将每个步骤包装在一个尝试捕获中;根据代码的运行方式,您可以一次看到这样做的问题。
我相信这里最重要的部分是对读者采取的行动。出于某种原因,读卡器在调用时似乎没有关闭流。默认情况下关闭()。
***在生产环境中运行时,我仍然注意到一个文件(无论如何,到目前为止)在关闭后尝试删除时仍然保持锁定。我添加了一个等待几秒钟再重试的捕获。这似乎对那些更“顽固”的文件起到了作用。
找出哪些itext7类实现IDisposable(从文档或Visual Studio对象浏览器等中),并确保在using blocks中使用它们,与在StreamReader中使用blocks的方式相同。
编辑:@sourkrause的解决方案可以缩短为:
using (reader = Helpers.GetPdfReader(formPath))
using (writer = new PdfWriter(newFilePath))
using (document = new PdfDocument(reader, writer))
{
// The rest of the code here
}
我有一些代码,正在尝试从一个可能或可能没有加密的文件读取。如果它是加密的,那么它在实际数据之前有一个包含几个字节信息的头。访问该文件的逻辑如下所示: 我的问题是: 我的假设是否正确,即关闭文件然后立即打开文件的代码可能会收到此错误,因为Windows仍在释放它,即使.NET Stream.Close方法调用已返回(或using块已退出)? 有没有比延长重试间隔更不垃圾的方法呢?
想改进这个问题吗 通过编辑此帖子,添加详细信息并澄清问题。 我想进行联调。我目前的方法: 我放置了@AutoConfigreMockMvc,但MockMvc对象仍然为空
想改进这个问题吗?更新问题,使其仅通过编辑这篇文章来关注一个问题。 我有一个PDF文档,有两页。我需要阅读此文档的第一页,并使用阅读内容创建一个新的PDF文档。我将如何使用iText执行此操作?到目前为止,我无法尝试任何事情,因为我真的不知道如何开始。最好的方法是什么?
我正在试图找到一种方法,以锁定一个签名和认证的PDF修改使用iText的方式,像Abode Reader DC这样的观众告诉我该文档是不开放的修改像这样 (如果我使用Adobe签署文档,我就可以这样做)使用PDF版本1.7和iText版本7.1.6。 然而,当我认证并签署我的pdf文件时,我的结果是: 在处理过程中,首先使用认证签名对此PDF进行签名,认证级别设置为form filling。 之后
我在Jpa存储库中使用Spring Boot。我在循环中保存一些记录,在保存所有记录后,会打印下面的异常。 JAVAsql。SQLRecoverableException:oracle的Instruço Fechada。jdbc。驾驶员OracleClosedStatement。oracle上的getMaxRows(OracleClosedStatement.java:3578)~[ojdbc6-
在对PDF文档进行数字签名后,我在Apache PDFBox中关闭了PDF文档。我收到警告: