【问题标题】:cannot access closed file itextsharp无法访问已关闭的文件 itextsharp
【发布时间】:2017-03-21 07:04:53
【问题描述】:

我正在尝试获取所有图像 pdf 并在该图像上方写一些文本。我正在使用以下代码但收到 “无法访问关闭的文件”错误

private static void InsertTextToPdf(string sourceFileName, string newFileName)
        {
            var img = new ReadPDFContent.ImagePDF.MyImageRenderListener();
            using (Stream pdfStream = new FileStream(sourceFileName, FileMode.Open))

                using (Stream newpdfStream = new FileStream(newFileName, FileMode.Create, FileAccess.ReadWrite))
                {

                    PdfReader pdfReader = new PdfReader(pdfStream);
                    PdfStamper pdfStamper = new PdfStamper(pdfReader, newpdfStream);

                    PdfContentByte pdfContentByte = pdfStamper.GetOverContent(1);
                    BaseFont baseFont = BaseFont.CreateFont(BaseFont.TIMES_ROMAN, BaseFont.CP1250, BaseFont.NOT_EMBEDDED);
                    pdfContentByte.SetColorFill(BaseColor.BLUE);
                    pdfContentByte.SetFontAndSize(baseFont, 8);
                    pdfContentByte.BeginText();
                    pdfContentByte.ShowTextAligned(PdfContentByte.ALIGN_CENTER, " ", 400, 600, 0);

                    Dictionary<string, System.Drawing.Image> images;
                    images = new Dictionary<string, System.Drawing.Image>();
                    using (var reader = new PdfReader(sourceFileName))
                    {
                        var parser = new iTextSharp.text.pdf.parser.PdfReaderContentParser(reader);
                        ImageRenderListener listener = null;
                        for (var i = 1; i <= reader.NumberOfPages; i++)
                        {
                            parser.ProcessContent(i, (listener = new ImageRenderListener()));
                            var index = 1;
                            if (listener.Images.Count > 0)
                            {

                                try
                                {

                                    var image = iTextSharp.text.Image.GetInstance(pdfStream);
                                        float xval = image.AbsoluteX;
                                        float yval = image.AbsoluteY;
                                        image.SetAbsolutePosition(xval, yval);
                                        pdfContentByte.ShowText("rahul");

                                }
                                catch (Exception e)
                                {
                                    Console.WriteLine(e.Message);
                                }

                            }
                        }
                    }
                    pdfContentByte.EndText();
                    pdfStamper.Close();
                }
            }

错误在以下行:

iTextSharp.text.Image.GetInstance(pdfStream);

在调试中我发现实际读取的文件,在 pdfreader 读取流后,seek 设置为 false。

【问题讨论】:

    标签: c# pdf itext


    【解决方案1】:

    为什么关门?

    这很简单:每当PdfReaderStream 构造时,该流在被读取到末尾后关闭。因此,在

    PdfReader pdfReader = new PdfReader(pdfStream);
    

    pdfStream 已关闭。


    是的,这确实与声称“流已读到最后但未关闭”的源代码注释相矛盾:

    /**
     * Reads and parses a PDF document.
     * @param isp the <CODE>InputStream</CODE> containing the document. The stream is read to the
     * end but is not closed
     * @throws IOException on error
     */
    public PdfReader(Stream isp) : this(isp, null) {
    }
    
    /**
     * Reads and parses a PDF document.
     * @param is the <CODE>InputStream</CODE> containing the document. The stream is read to the
     * end but is not closed
     * @param ownerPassword the password to read the document
     * @throws IOException on error
     */
    public PdfReader(Stream isp, byte[] ownerPassword) : this(
        new RandomAccessSourceFactory().CreateSource(isp),
        false,
        ownerPassword,
        null,
        null,
        false) {
    }
    

    但是查看使用过的RandomAccessSourceFactory 方法CreateSource 重载可以看到:

    /**
     * Creates a {@link RandomAccessSource} based on an {@link InputStream}.  The full content of the InputStream is read into memory and used
     * as the source for the {@link RandomAccessSource}
     * @param is the stream to read from
     * @return the newly created {@link RandomAccessSource}
     */
    public IRandomAccessSource CreateSource(Stream inp) {
        try {
            return CreateSource(StreamUtil.InputStreamToArray(inp));
        }
        finally {
            try {inp.Close();}catch{}
        }       
    } 
    

    即一个强制的Close

    尝试重用

    也就是说,如果文件没有关闭,你只会有一个不同的例外。

    期间

    PdfReader pdfReader = new PdfReader(pdfStream);
    

    流被读到最后,所以这里

    var image = iTextSharp.text.Image.GetInstance(pdfStream);
    

    不会从流中读取任何内容。

    即使您确实在Image.GetInstance 之前将流重置为开始,您也会遇到另一个例外:流内容是PDF 或位图图像。如果是PDF,Image.GetInstance会失败;如果它是位图,new PdfReader 将失败(假设您不使用那些通过网格划分格式既被接受为位图又被接受为 PDF 的构造文件之一)

    任务

    关于在文件中在图像上方写入一些文本的任务,您可以通过创建自定义渲染侦听器(而不是使用忽略图像坐标的现有渲染侦听器)来做到这一点,例如像这样:

    public class ImageEntitlingRenderListener : IRenderListener
    {
        BaseFont baseFont = BaseFont.CreateFont(BaseFont.TIMES_ROMAN, BaseFont.CP1250, BaseFont.NOT_EMBEDDED);
        PdfStamper pdfStamper = null;
        int page = 0;
    
        public ImageEntitlingRenderListener(PdfStamper pdfStamper, int page)
        {
            this.pdfStamper = pdfStamper;
            this.page = page;
        }
    
        public void RenderImage(ImageRenderInfo renderInfo)
        {
            Matrix ctm = renderInfo.GetImageCTM();
            float xCenter = ctm[Matrix.I31] + 0.5F * ctm[Matrix.I11];
            float yTop = ctm[Matrix.I32] + ctm[Matrix.I22];
            PdfContentByte pdfContentByte = pdfStamper.GetOverContent(page);
            pdfContentByte.SetColorFill(BaseColor.BLUE);
            pdfContentByte.SetFontAndSize(baseFont, 8);
            pdfContentByte.BeginText();
            pdfContentByte.ShowTextAligned(PdfContentByte.ALIGN_CENTER, "rahul", xCenter, yTop, 0);
            pdfContentByte.EndText();
        }
    
        public void BeginTextBlock() { }
        public void EndTextBlock() { }
        public void RenderText(TextRenderInfo renderInfo) { }
    }
    

    你可以这样使用它:

    private static void InsertTextToPdf(string sourceFileName, string newFileName)
    {
        using (Stream pdfStream = new FileStream(sourceFileName, FileMode.Open))
        using (Stream newpdfStream = new FileStream(newFileName, FileMode.Create, FileAccess.ReadWrite))
        {
            PdfReader pdfReader = new PdfReader(pdfStream);
            PdfStamper pdfStamper = new PdfStamper(pdfReader, newpdfStream);
    
            var parser = new PdfReaderContentParser(pdfReader);
            for (var i = 1; i <= pdfReader.NumberOfPages; i++)
            {
                parser.ProcessContent(i, (new ImageEntitlingRenderListener(pdfStamper, i)));
            }
            pdfStamper.Close();
            pdfReader.Close();
        }
    }
    

    请注意,代码中有一些简化假设。特别是它假定图像在 PDF 中是直立绘制的。您可能希望改进代码以实现更通用的用途。

    【讨论】:

    • 你能帮我解决这个问题吗,stackoverflow.com/questions/42926482/…
    • @rahularyansharma 首先,这里的答案是否回答了您的问题?如果是,请接受。如果不是,请解释一下。
    • 确实如此,但我不确定如何使其成为可行的解决方案而不是错误。是的,你解释了它为什么关闭,但我希望 stackoverflow 是解决方案的站点。
    • 我刚刚为您的任务添加了一个概念验证到答案中。但是,您真的不应该对答案集中在您在问题中关注的问题上感到惊讶,而且您的问题显然集中在您想要访问某个流时已关闭的事实。
    猜你喜欢
    • 2022-11-14
    • 1970-01-01
    • 2012-10-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多