【问题标题】:System.IO.IOException: lock PDF fileSystem.IO.IOException:锁定 PDF 文件
【发布时间】:2016-02-12 11:59:51
【问题描述】:

我构建了两个 .Net 应用程序来创建 pdf 电子保修。为了创建 pdf,我使用与 OpenCart 集成的 Web API 2.0 服务,一切正常。为了填写 pdf,我创建了第二个应用程序 - ASP.NET Web Forms,这是锁定 pdf 文件的问题。

当我打开一个文件并填写一些字段时,然后将信息保存到数据库 - 一切都很好。但是,如果我想在同一个 pdf 抛出异常上添加其他信息:

System.IO.IOException:进程无法访问文件“...\AllWarranties\2016\2\000077.pdf”,因为它正被另一个进程使用。

只有当应用程序在服务器上时才会发生这种情况!什么时候在本地机器上没有问题。我研究并发现打开应用程序时会启动 w3wp.exe 进程。如果我终止此进程,则 pdf 将被解锁。我在应用程序轮询中将空闲超时设置为 1 分钟,但这不是解决方案。

问题是:lock pdf 的问题在哪里?是在过程中还是在我身上?也许我没有关闭一些东西。

我使用 iTextSharp 来填充 pdf。

使用 MemoryStream 编辑代码

        string pdfDirectory = @"C:\Projects\Amco\EWarranty\EWarranty" + currentFilePath.FilePath;

        MemoryStream inputMemoryStream = new MemoryStream();

        using (FileStream fs = File.OpenRead(pdfDirectory))
        {
            inputMemoryStream.SetLength(fs.Length);
            fs.Read(inputMemoryStream.GetBuffer(), 0, (int)fs.Length);
            inputMemoryStream.Seek(0, SeekOrigin.Begin);
        }

        PdfReader pdfReader = new PdfReader(inputMemoryStream);

        using (Stream inputImageStream = new FileStream(@"C:\Projects\Amco\EWarranty\pechatAMCO.png", FileMode.Open, FileAccess.Read, FileShare.Read))
        using (MemoryStream outputStream = new MemoryStream())
        {
            using (PdfStamper pdfStamper = new PdfStamper(pdfReader, outputStream))
            {
                if (currentServiceMap.FailureNumber == 0)
                {
                    var pdfContentByte = pdfStamper.GetOverContent(3);

                    Image image = Image.GetInstance(inputImageStream);
                    image.ScaleToFit(150, 150);
                    image.SetAbsolutePosition(140, 425);
                    pdfContentByte.AddImage(image);
                }

                // Some other else if statements ...

                AcroFields pdfFormFields = pdfStamper.AcroFields;

                BaseFont cyrillicFont = BaseFont.CreateFont(@"C:\Windows\Fonts\Arial.ttf", BaseFont.IDENTITY_H, BaseFont.EMBEDDED);

                pdfFormFields.AddSubstitutionFont(cyrillicFont);

                // first fail
                if (txt_First_Adoption_Date.Text != "")
                {
                    pdfFormFields.SetField("firstAdoptionDate", txt_First_Adoption_Date.Text);
                }

                if (txt_First_Failure.Text != "")
                {
                    pdfFormFields.SetField("firstFailure", txt_First_Failure.Text);
                }

                if (txt_First_Return_Date.Text != "")
                {
                    pdfFormFields.SetField("firstReturnDate", txt_First_Return_Date.Text);
                }

                // Second, third and so on failds ...

                warrantyService.UpdateServiceMapByAdmin(CurrentSessions.warrantyNumber, txt_First_Adoption_Date.Text, txt_First_Failure.Text, "", txt_First_Return_Date.Text, txt_Second_Adoption_Date.Text, txt_Second_Failure.Text,
                                                            "", txt_Second_Return_Date.Text, txt_Third_Adoption_Date.Text, txt_Third_Failure.Text, "", txt_Third_Return_Date.Text, txt_Fourth_Adoption_Date.Text, txt_Fourth_Failure.Text,
                                                            "", txt_Fourth_Return_Date.Text, txt_Fifth_Adoption_Date.Text, txt_Fifth_Failure.Text, "", txt_Fifth_Return_Date.Text, (currentServiceMap.FailureNumber + 1));

                pdfStamper.FormFlattening = false;
            }

            byte[] pdfContent = outputStream.ToArray();

            File.WriteAllBytes(pdfDirectory, pdfContent);
        }

        pdfReader.Close();

        inputMemoryStream.Close();

【问题讨论】:

    标签: c# asp.net pdf itextsharp


    【解决方案1】:

    你忘记了这一行:

    pdfReader.Close();
    

    执行此操作时,文件将被释放。如果你省略这个,文件也可以被释放,但很难预测什么时候。显然,该文件会在您的本地计算机上快速发布;但它在您的服务器上保持打开的时间更长。

    如果不关闭 PdfStamper 实例,我也不明白您的代码如何工作。你不应该在处理pdfStamper之前添加这一行吗:

    pdfStamper.Close();
    

    也许这一行不是绝对必要的(在 iText 的 Java 版本中是必需的),但添加它并没有什么坏处。

    更新:您指的是一个名为 w3wp.exe 的进程。 What is w3wp.exe?

    Internet 信息服务 (IIS) 工作进程是运行 Web 应用程序的 Windows 进程 (w3wp.exe),负责处理发送到特定应用程序池的 Web 服务器的请求。

    就 iTextSharp 而言,您在磁盘上有一个已发布的文件,但该文件已被您的 Web 服务器 (IIS) 锁定。为什么将文件存储在磁盘上?如果您将文件保存在内存中,您不会避免这个问题吗?我不知道你申请的完整流程,所以我无法回答这部分问题。

    【讨论】:

    • 我将文件存储在磁盘上,因为这是客户想要的功能。我不知道您将文件保存在内存中是什么意思-可能存储在会话中然后存储到磁盘,还是什么?今天我测试了应用程序,当对一个 pdf 进行更改时,然后去对另一个进行更改,然后第一个被发布,我可以再次进行更改。再次感谢您的帮助!
    • 您将 PDF 写入FileStream。当我说“将文件保存在内存中”时,我的意思是您也可以将 PDF 写入MemoryStream。然后您可以使用内存中的字节 (1.) 将它们发送给最终用户,(2.) 将它们加载到 PdfReader 以更改文件,(3.) 将字节存储到磁盘中的文件中。
    • 我用MemoryStream 更改了我的代码,但我不知道结构是否正确。但是,现在当我第二次去更改字段时,我在File.WriteAllBytes(pdfDirectory, pdfContent); 上得到了例外。我哪里错了?在某些特定点或所有解决方案都是错误的?
    • 你有同样的例外吗?无论如何:我们现在已经确定该问题与 iTextSharp 无关:您只需将字节写入同一文件两次即可重现它。您为什么不发布另一个问题,例如“为什么 IIS 不在服务器上发布文件?”带有标签 IIS、ASP、文件。
    • 是的,例外是一样的。按照建议,我发布了另一个问题。 Why doesn't IIS release files on the server?
    猜你喜欢
    • 1970-01-01
    • 2021-03-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-02-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多