PdfDocument关闭后仍保持锁定

时间:2018-07-10 15:53:45

标签: c# .net itext7

我有一个Windows服务,可以将PDF动态合并在一起,然后将其移动到另一个位置。在大多数情况下,我无法控制要合并的内容。曾经发生过的情况是,经常会处理损坏的PDF,因此创建新的PdfDocument会引发PdfException“未找到挂车”。我正在捕获异常并关闭文档,但是在关闭PDF本身后它仍然以某种方式锁定。我需要删除目录,但在尝试执行该操作时,它将引发IOException并使服务崩溃。

我已经验证了调用PdfDocument构造函数可以锁定pdf,并且在关闭文件后立即保持锁定状态。

有什么想法吗? iText是否可以提供帮助,还是我需要在我附近检查损坏的PDF的地方进行一些工作?

ProcessDirectory


    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在处置PdfDocument时不处置单个PdfReader和PdfWriter的原因,我以为是这样。

1 个答案:

答案 0 :(得分:2)

从文档或Visual Studio对象浏览器等中找出哪个itext7类实现IDisposable,并确保您在using块中使用它们,就像您已经为StreamReader使用块一样。

编辑:@sourkrause的解决方案可以简化为:

using (reader = Helpers.GetPdfReader(formPath))
using (writer = new PdfWriter(newFilePath))
using (document = new PdfDocument(reader, writer))
{
    // The rest of the code here
}