2015-11-06 18 views
8

Der folgende Code verwendet verfügen zusammen bestehende PDFs zum Aufnähen [Als Neben wir TallComponents werden mit dem eigentlichen Nähen zu tun, falls Sie sich fragen, was PDFUtility ist]:Wie aus einem Objekt Memory

PDFUtility.Document docFinal = new PDFUtility.Document(); 
PDFUtility.Document docToAdd = null; 
byte[] combinedFile; 

foreach (byte[] content in fileContents) 
{ 
    MemoryStream fileContentStream = new MemoryStream(content); 
    docToAdd = new PDFUtility.Document(fileContentStream); 
    docFinal.Pages.AddRange(docToAdd.Pages.CloneToArray()); 
} 
using (MemoryStream stream = new MemoryStream()) 
{ 
    docFinal.Write(stream); 
    combinedFile = stream.ToArray(); 
} 

Das eklatante Problem mit diesem Code ist dieser Befehl:

MemoryStream fileContentStream = new MemoryStream(content); 

Der Speicherstrom fileContentStream nicht angeordnet zu werden, möglicherweise (glaube ich) auf Findmittel hält länger als nötig.

Die naheliegende Lösung wäre, die Erstellung des MemoryStream in einen using Block zu wickeln. Der Code würde dann wie folgt aussehen:

PDFUtility.Document docFinal = new PDFUtility.Document(); 
PDFUtility.Document docToAdd = null; 
byte[] combinedFile; 

foreach (byte[] content in fileContents) 
{ 
    using (MemoryStream stream = new MemoryStream()) 
    { 
     MemoryStream fileContentStream = new MemoryStream(content); 
     docToAdd = new PDFUtility.Document(fileContentStream); 
     docFinal.Pages.AddRange(docToAdd.Pages.CloneToArray()); 
    } 
} 
using (MemoryStream stream = new MemoryStream()) 
{ 
    docFinal.Write(stream); 
    combinedFile = stream.ToArray(); 
} 

Die Verwendung des mit Block in dem obigen Code bewirkt, dass der Code auf dieser Linie scheitern (weil die Ströme vorher angeordnet wurden):

docFinal.Write(stream); 

One Mögliche Lösung wäre, alle MemoryStream-Instanzen zu verfolgen und sie nach zu entsorgen. Dies ist der Code dafür:

PDFUtility.Document docFinal = new PDFUtility.Document(); 
PDFUtility.Document docToAdd = byte[] combinedFile; 
List<MemoryStream> streams = new List<MemoryStream>(); 
foreach (byte[] content in fileContents) 
{ 
    MemoryStream fileContentStream = new MemoryStream(content); 
    streams.Add(fileContentStream); //EACH INSTANCE OF A STREAM IS TRACKED 
    docToAdd = new PDFUtility.Document(fileContentStream); 
    docFinal.Pages.AddRange(docToAdd.Pages.CloneToArray()); 
} 
using (MemoryStream stream = new MemoryStream()) 
{ 
    docFinal.Write(stream); 
    combinedFile = stream.ToArray(); 
} 
streams.ForEach(s => s.Dispose()); //DISPOSE OF ALL STREAMS HERE 

Der obige Code funktioniert. Ich verzögere einfach den Dispose, bis das letzte Dokument geschrieben ist.

Dies scheint jedoch nicht die "beste" Lösung. Gibt es eine Möglichkeit Block zu implementieren mit (und damit garantiert die Objekte ordnungsgemäß entsorgt werden?

+0

Gibt es irgendeine Art von 'docFInal.Flush' Methode, die Sie aufrufen können, bevor Sie die Schleife verlassen? –

+0

Siehe [MemoryStream muss explizit entsorgt werden?] (Http://stackoverflow.com/questions/4195746/memorystream-must-be-explicitely-be- disposed). – MicroVirus

+1

Und noch eins (scheint aktiver zu sein) http://stackoverflow.com/questions/234059/is-a-memory-leak-created-if-a-memorystream-in-net-is-not-closed – shurik

Antwort

5

using Blöcke sind nicht viel mehr als syntaktischer Zucker für try-finally Blöcke.

Je nachdem, wie die Verwendung von Block verwendet wird, können Sie am Ende up mit zwei Arten von try-finally-Blöcken

Fall 1:.

// This code ... 
using(var thing = new Thing()) { 
    thing.DoOperation(); 
} 

// ... turns into this scoped try-finally: 
{ 
    var thing = new Thing(); 
    try { 
     thing.DoOperation(); 
    } 
    finally { 
     thing.Dispose(); 
     thing = null; 
    } 
} 

Fall zwei:

// This code ... 
var thing = new Thing(); 
using(thing) { 
    thing.DoOperation(); 
} 

// ... turns into this code 
var thing = new Thing(); 
try { 
    thing.DoOperation(); 
} 
finally { 
    thing.Dispose(); 
    // Note the lack of a null assignment. 
} 

Mit diesem Wissen können Sie Ihre dritte Lösung ändern, um einen finally Block zu verwenden, um sicherzustellen, dass Ihre MemoryStream Objekte immer bereinigt werden.

PDFUtility.Document docFinal = new PDFUtility.Document(); 
PDFUtility.Document docToAdd = byte[] combinedFile; 
List<MemoryStream> streams = new List<MemoryStream>(); 

try 
{ 
    foreach (byte[] content in fileContents) 
    { 
     MemoryStream fileContentStream = new MemoryStream(content); 
     streams.Add(fileContentStream); //EACH INSTANCE OF A STREAM IS TRACKED 
     docToAdd = new PDFUtility.Document(fileContentStream); 
     docFinal.Pages.AddRange(docToAdd.Pages.CloneToArray()); 
    } 
    using (MemoryStream stream = new MemoryStream()) 
    { 
     docFinal.Write(stream); 
     combinedFile = stream.ToArray(); 
    } 

} 
finally 
{ 
    streams.ForEach(s => s.Dispose()); //DISPOSE OF ALL STREAMS HERE 
}