Peter Peter - 1 month ago 14
C# Question

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.

Answer

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();
     }

     // ...
}