簡體   English   中英

使用iTextSharp多次寫入包含字段的PDF文件

[英]Write to a PDF file with fields multiple times using iTextSharp

我有一個PDF文檔,其中包含3個字段txt_FirstNametxt_MiddleNametxt_LastName ,我使用iTextSharp寫入。

我有一個循環,創建輸出文件,寫入它,並關閉文件。

第一次在循環中,文件寫入名字和中間名。

在循環中第二次,文件應該具有名字,中間名,並寫下姓氏。

問題:問題是,當它第二次進入循環時,將姓氏寫成名字,中間名稱消失。

目標:我想做的主要是多次寫入相同的PDF文檔

下載PDF模板: https //www.scribd.com/document/412586469/Testing-Doc

    public static string templatePath = "C:\\temp\\template.pdf";
    public static string OutputPath = "C:\\Output\\";

    private static void Fill_PDF()
    {
        string outputFile = "output.pdf";
        int counter = 1;

        for (int i = 0; i < 2; i++)
        {
            PdfStamper pdfStamper;
            PdfReader reader;

            reader = new PdfReader(File.ReadAllBytes(templatePath));
            PdfReader.unethicalreading = true;

            if (File.Exists(OutputPath + outputFile))
            {
                pdfStamper = new PdfStamper(reader, new FileStream(OutputPath + outputFile,
                                                        FileMode.Append, FileAccess.Write));
            }
            else
            {
                pdfStamper = new PdfStamper(reader, new FileStream(OutputPath + outputFile,
                                                        FileMode.Create));
            }
            AcroFields pdfFormFields = pdfStamper.AcroFields;

            if (counter == 1)
            {
                pdfFormFields.SetField("txt_FirstName", "Scooby");
                pdfFormFields.SetField("txt_MiddleName", "Dooby");
                counter++;
            }
            else if (counter == 2)
            {
                pdfFormFields.SetField("txt_LastName", "Doo");
            }
            pdfStamper.Close();
        }
    }

這似乎是一個簡單的錯誤。 第一次循環時,加載空白模板並寫入第一個和中間名。 第二次循環, 再次加載空白模板寫入姓氏 ,然后保存到相同的文件名,覆蓋它。 如果,在第二次循環中,您要加載已包含第一個和中間名的文件,則必須加載第一次編寫的輸出文件 ,而不是再次加載空白模板。 或者,如果要再次加載空白模板,在if (counter == 2)子句中,您將不得不編寫所有3個名稱,而不僅僅是姓氏。

我復制了你的bug,讓它運行起來。 這是我描述的第一個解決方案的代碼(對代碼的小修改):

    public static string templatePath = "C:\\temp\\template.pdf";
    public static string OutputPath = "C:\\temp\\output\\";

    private static void Fill_PDF()
    {
        string outputFile = "output.pdf";
        int counter = 1;

        for (int i = 0; i < 2; i++)
        {
            PdfStamper pdfStamper;
            PdfReader reader = null;

            /********** here's the changed part */
            if (counter == 1)
            {
                reader = new PdfReader(File.ReadAllBytes(templatePath));
            } else if (counter == 2)
            {
                reader = new PdfReader(File.ReadAllBytes(OutputPath + outputFile));
            }
            /************ end changed part */

            PdfReader.unethicalreading = true;

            if (File.Exists(OutputPath + outputFile))
            {
                pdfStamper = new PdfStamper(reader, new FileStream(OutputPath + outputFile,
                    FileMode.Append, FileAccess.Write));
            }
            else
            {
                pdfStamper = new PdfStamper(reader, new FileStream(OutputPath + outputFile,
                    FileMode.Create));
            }
            AcroFields pdfFormFields = pdfStamper.AcroFields;

            if (counter == 1)
            {
                pdfFormFields.SetField("txt_FirstName", "Scooby");
                pdfFormFields.SetField("txt_MiddleName", "Dooby");
                counter++;
            }
            else if (counter == 2)
            {
                pdfFormFields.SetField("txt_LastName", "Doo");
            }
            pdfStamper.Close();
        }
    }

代碼有兩個主要問題。 @Nick在他的回答中已經指出了第一個:如果在第二遍中你想要編輯包含第一遍的變化的文檔版本,你必須將第一遍的輸出文檔作為第二遍的輸入,不是原始模板。 他還提出了修復此問題的代碼。

第二個問題位於:

if (File.Exists(OutputPath + outputFile))
{
    pdfStamper = new PdfStamper(reader, new FileStream(OutputPath + outputFile,
                                            FileMode.Append, FileAccess.Write));
}
else
{
    pdfStamper = new PdfStamper(reader, new FileStream(OutputPath + outputFile,
                                            FileMode.Create));
}

如果輸出文件已存在, PdfStamper的輸出附加到其中 這是錯的! PdfStamper的輸出已包含原始PDF(來自PdfReader )的內容,只要它們沒有被更改。 因此,您的代碼有效地生成第一遍的完整輸出PDF和第二遍的完整輸出PDF的串聯。

PDF是一種二進制格式,其中的連接文件不會生成有效的PDF文件。 因此,加載最終結果的PDF查看器會嘗試修復此雙PDF,假設它是單個PDF。 結果可能或可能不是您想要的結果。

要解決第二個問題,只需將if{...}else{...}替換為else分支的內容:

pdfStamper = new PdfStamper(reader, new FileStream(OutputPath + outputFile,
                                        FileMode.Create));

FileMode.Create定義為

指定操作系統應創建新文件。 如果該文件已存在,則將被覆蓋。 這需要Write權限。 FileMode.Create等同於請求如果文件不存在,則使用CreateNew ; 否則,請使用Truncate 如果文件已存在但是是隱藏文件,則拋出UnauthorizedAccessException異常。

因此,如果已有文件,它也會執行所需的操作。)

您可以通過運行它幾次來識別代碼中包含Append的問題,並觀察輸出文件的增長和增長超出需要。 此外,如果您在Adobe Reader中打開該文件並再次關閉,Adobe Reader會保存更改; 變化是修復工作。


您可能聽說過改變附加到原始PDF PDF文件的增量更新 但這與僅僅連接不同,結果中的修訂是特殊關聯的,並且偏移總是從第一次修訂的開始計算,而不是從當前修訂的開始計算。 此外,增量更新應僅包含已更改的對象。

iText包含一個帶有4個參數的PdfStamper構造函數,包括最后一個布爾參數append 使用該構造函數並將append設置為true會使iText創建增量更新。 但即使在這里你也不要使用FileMode.Append ......

問題是再次使用模板文件進行第二次迭代。

第一次迭代:按預期正常工作!

第二次迭代:您正在讀取相同的文件並僅寫入姓氏。 最后,將替換在第一次迭代中創建的輸出文件。

修復:在知道輸出文件是否存在於該位置后,選擇要讀取的文件源,如下所示。 這應該可以解決問題。 親自檢查,它的工作原理!

if (File.Exists(OutputPath + outputFile))
{
    reader = new PdfReader(File.ReadAllBytes(OutputPath + outputFile));
    pdfStamper = new PdfStamper(reader, new FileStream(OutputPath + outputFile,
                                                            FileMode.Append, FileAccess.Write));
}
else
{
    reader = new PdfReader(File.ReadAllBytes(templatePath));
    pdfStamper = new PdfStamper(reader, new FileStream(OutputPath + outputFile,
                                                            FileMode.Create));
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM