Laden einer Datei in eine Bitmap, wobei die ursprüngliche Datei intakt bleibt

7

Wie geht das in C #?

Wenn ich Bitmap.FromFile () verwende, ist die ursprüngliche Datei gesperrt.

Wenn ich Bitmap.FromStream () verwende, ist die ursprüngliche Datei nicht gesperrt, aber in der Dokumentation steht "Sie müssen den Stream für die gesamte Lebensdauer des Image geöffnet lassen". Dies bedeutet wahrscheinlich, dass die Datei immer noch mit dem Bildobjekt verknüpft ist (zum Beispiel, wenn sich die Datei ändert, ändert sich das Objekt oder umgekehrt).

Ich möchte nur die Bitmap lesen und sie in einem Objekt speichern und danach gibt es keinerlei Verbindung zwischen der Datei und dem Image-Objekt

    
Louis Rhys 02.08.2010, 10:11
quelle

4 Antworten

25

Einige Hintergrundinformationen zu diesem Verhalten: Bitmap verwendet eine speicherdefinierte Datei, um auf die Pixel in der Bitmap zuzugreifen. Das ist eine sehr einfache Einrichtung in der Windows-API, die eine sehr effiziente Zuordnung von Speicher zu Dateidaten ermöglicht. Daten werden nur aus der Datei gelesen, wenn das Programm den Speicher liest. Die virtuellen Speicherseiten nehmen in der Windows-Auslagerungsdatei keinen Platz ein.

Derselbe Mechanismus wird zum Laden von .NET-Assemblys verwendet. Es ist die Speicherzuordnung, die eine Sperre für die Datei festlegt. Aus diesem Grund sind Assemblys gesperrt, wenn sie in einem .NET-Programm verwendet werden. Die Image.Dispose () -Methode gibt die Sperre frei. Wenn Sie die Sperre bekämpfen, werden Sie häufig vergessen, Ihre Bitmaps zu löschen. Sehr wichtig, das Vergessen, Dispose () zu verwenden, verursacht nicht oft Probleme für .NET-Klassen, außer für Bitmap, da es so viel (nicht verwalteten) Speicher benötigen kann.

Ja, FromStream () verhindert, dass die Klasse diese Optimierung durchführt. Die Kosten sind beträchtlich. Sie benötigen den doppelten Speicher, wenn die Bitmap geladen wird. Dies ist ein Problem, wenn die Bitmap groß ist. Sie befinden sich in der Nähe von OOM, wenn das Programm eine Zeit lang ausgeführt wurde (Fragmentieren des Adressraums), und es läuft nicht auf einem 64-Bit-Betriebssystem. Vermeiden Sie dies auf jeden Fall, wenn die Bitmap Breite x Höhe x 4 & gt; = 45 MB, geben oder übernehmen.

Bei einigen Codes müssen Sie nicht durch den CopyStream-Rahmen springen:

%Vor%

Beachten Sie, dass Sie den MemoryStream nicht löschen möchten. Sie werden einen schwer zu diagnostizierenden "generischen Fehler" bekommen, wenn Sie die Bitmap verwenden. Wird von der Image-Klasse verursacht, die den Stream liest.

    
Hans Passant 02.08.2010, 15:18
quelle
4

Lesen Sie die Datei in den Speicher, indem Sie sie von einem FileStream in ein MemoryStream kopieren. (Suchen Sie in Stack Overflow nach CopyStream , um viele Beispiele zu finden, wie Sie das sicher tun. Schleifen Sie grundsätzlich während des Lesens und schreiben Sie jeden Chunk in den Speicherstream, bis keine Daten mehr zu lesen sind.) Dann spulen Sie MemoryStream ( Setzen Sie Position = 0 ) und übergeben Sie das dann an Bitmap.FromStream .

    
Jon Skeet 02.08.2010 10:15
quelle
4

Um ein Bild zu erstellen, ohne die Datei zu sperren, müssen Sie eine Kopie des Image-FileStreams erstellen. Überprüfen Sie diese Seite Beste Möglichkeit zum Kopieren zwischen zwei Stream-Instanzen - C # zum Kopieren des Streams.

Erstellen Sie anschließend Ihr Bild aus dem kopierten Stream und Sie können loslegen.

    
Alex Essilfie 02.08.2010 10:40
quelle
0

Ich habe diese Technik des Kopierens zu MemoryStream verwendet und dann den MemoryStream ziemlich oft in Bitmap.FromStream eingespeist. Es gibt jedoch auch ein Problem mit dieser Technik.

Wenn Sie planen, zu einem späteren Zeitpunkt eine der Bitmap.Save-Methoden auf dem geladenen Bild zu verwenden, müssen Sie den Stream am Leben halten (dh Sie können ihn nicht nach dem Laden des Bildes löschen), sonst erhalten Sie die gefürchtete Ausnahme "A generic GDI + error occurred"!

    
Raghu 25.05.2011 00:34
quelle

Tags und Links