Peter
Peter

Reputation: 121

MemoryStream - Cannot access a closed Stream when merging PDFs

Can you please tell me, what's wrong with my code? I'm using it to merge PDFs, I create a memory stream then output it to PDF. It works fine for me, but some users cannot download file in IE, or get network error in Chrome:

public static MemoryStream MergePdfForms(List<byte[]> files)
    {
        if (files.Count > 1)
        {
            PdfReader pdfFile;
            Document doc;
            PdfWriter pCopy;
            MemoryStream msOutput = new MemoryStream();

            pdfFile = new PdfReader(files[0]);

            doc = new Document();
            pCopy = new PdfSmartCopy(doc, msOutput);

            doc.Open();

            for (int k = 0; k < files.Count; k++)
            {
                pdfFile = new PdfReader(files[k]);
                for (int i = 1; i < pdfFile.NumberOfPages + 1; i++)
                {
                    ((PdfSmartCopy)pCopy).AddPage(pCopy.GetImportedPage(pdfFile, i));
                }
                pCopy.FreeReader(pdfFile);
            }

            pdfFile.Close();
            pCopy.Close();
            doc.Close();

            return msOutput;
        }
        else if (files.Count == 1)
        {
            return new MemoryStream(files[0]);
        }

        return null;
    }

After debugging, I've noticed that the memory stream msOutput has some errors:

enter image description here

What's causing it, and how to avoid it?

Thank you.

Upvotes: 2

Views: 2036

Answers (1)

Matias Cicero
Matias Cicero

Reputation: 26281

Set CloseStream to false, otherwise the output stream will be closed when you call pCopy.Close().

pCopy = new PdfSmartCopy(doc, msOutput) { CloseStream = false };

Explanation

I found no documentation over the Internet so I had to look at the source code directly.

Here's the declaration of the PdfSmartCopy class:

public class PdfSmartCopy : PdfCopy
{
    // ...

    public PdfSmartCopy(Document document, Stream os) : base(document, os) {
        // ...
    }

    // ...
}

Here is the declaration of the PdfCopy class:

public class PdfCopy : PdfWriter
{
    // ...

    public PdfCopy(Document document, Stream os) : base(new PdfDocument(), os)     {
        // ...
    }

    // ...
}

The declaration of the PdfWriter class:

public class PdfWriter : DocWriter, 
    IPdfViewerPreferences,
    IPdfEncryptionSettings,
    IPdfVersion,
    IPdfDocumentActions,
    IPdfPageActions,
    IPdfIsoConformance,
    IPdfRunDirection,
    IPdfAnnotations
{
    // ...

    protected PdfWriter(PdfDocument document, Stream os) : base(document, os) {
        // ...
    }

    // ...
}

And finally, the declaration of DocWriter class:

public abstract class DocWriter : IDocListener
{
    // ...

    // default value is true
    protected bool closeStream = true;

    public virtual bool CloseStream {
        get {
            return closeStream;
        }
        set {
            closeStream = value;
        }
    }

     protected DocWriter(Document document, Stream os)  
     {
        this.document = document;
        this.os = new OutputStreamCounter(os);
     }

     public virtual void Close() {
        open = false;
        os.Flush();
        if (closeStream) // <-- Take a look at this line
            os.Close();
     }

     // ...
}

Upvotes: 2

Related Questions