Forum: PC-Programmierung [c#] Schließen des Basestream verhindern


von avr (Gast)


Lesenswert?

Hi

In meinem C# Programm lese ich zurzeit u.a. Mp3 Dateien ein, die intern 
nach Wave konvertiert werden. Das ganze Programm soll die Datei dann 
über einen MemoryStream benutzen. Das Problem ist nur, dass z.B. der 
BinaryReader den BaseStream schließt sobald er freigegeben wird. Damit 
ist mein MemoryStream weg. Kann man das irgendwie verhindern? Die 
Notlösung wäre den Stream zu kopieren, aber das kostet gerade bei 
längeren Mp3-Dateien viel zu viel Ram.

von bluppdidupp (Gast)


Lesenswert?

avr schrieb:
> Das Problem ist nur, dass z.B. der
> BinaryReader den BaseStream schließt sobald er freigegeben wird

Bei einem der Konstruktoren kann man angeben ob er das tun soll.
(Warum bei mp3s nicht einfach nen FileStream nehmen?)

von Markus V. (valvestino)


Lesenswert?

Warum lässt Du Dir vor dem Schließen des BinaryReaders nicht den Buffer 
des MemoryStream-Objekts geben, sei es über Read oder besser ToArray? 
Dann kann der Stream Disposed werden und Du hast trotzdem Deine Daten 
zur Verfügung und könntest Damit auch wieder einen neuen MemoryStream 
öffnen.

Grüße
Markus

von avr (Gast)


Lesenswert?

bluppdidupp schrieb:
> Bei einem der Konstruktoren kann man angeben ob er das tun soll.

Danke das funktioniert zwar, aber anscheinend nur bei .NET 4.5.

Markus Volz schrieb:
> Warum lässt Du Dir vor dem Schließen des BinaryReaders nicht den
> Buffer
> des MemoryStream-Objekts geben, sei es über Read oder besser ToArray?

An dieser Lösung gefällt mir nicht, dass kurzzeitig die Daten doppelt im 
Ram stehen, d.h. das Programm benötigt doppelt so viel Speicher. Und 
Große Wave-Dateien im Ram sind sowieso schon recht groß.

von bluppdidupp (Gast)


Lesenswert?

Man könnte sich vermutlich auch ne Klasse "FakeStream" oder so basteln, 
die intern auf dem echten Stream arbeitet, aber bei .Close() einfach 
nichts tut - und den FakeStream gibt man dann dem BinaryReader.

von Uhu U. (uhu)


Lesenswert?

avr schrieb:
> An dieser Lösung gefällt mir nicht, dass kurzzeitig die Daten doppelt im
> Ram stehen, d.h. das Programm benötigt doppelt so viel Speicher.

Hast du nachgeprüft, daß das MemoryStream-Objekt kopiert wird?

von Udo S. (urschmitt)


Lesenswert?

ich kenne jetzt nur Java und C# nicht besonders, aber
sollte man nicht einfach mit

newStream = new MemoryStream(oldStream.getBuffer())

sich ein 2. Memory Stream Objekt machen können, das das gleiche darunter 
liegende ByteArray benutzt.
Dadurch dürfte eigentlich kein Speicher dupliziert werden wenn ich die 
Doku beim Überfliegen richtig verstanden habe.

Nachtrag: Ich würde dann sogar soweit gehen und immer einen 2tes 
Streamobjekt auf den Buffer erzeugen das zum Lesen benutzt wird. So 
bleibt das Original das beim Konvertieren erzeugt wurde solange bestehen 
bis du es explizit wegwirfst.

: Bearbeitet durch User
von Markus V. (valvestino)


Lesenswert?

avr schrieb:
> An dieser Lösung gefällt mir nicht, dass kurzzeitig die Daten doppelt im
> Ram stehen, d.h. das Programm benötigt doppelt so viel Speicher. Und
> Große Wave-Dateien im Ram sind sowieso schon recht groß.

Für solche Infos gibt's die MSDN Doku. ;-) Dort steht ganz klar: 
GetBytes() liefert den über die Konstruktoren übergebenen bzw. den 
intern erzeugten Buffer falls keiner übergeben wurde. Dagegen liefert 
ToArray eine Kopie des Buffers. Bei GetBuffer ist allerdings das 
Problem, dass der dieser i.d.R. größer ist, als er Daten enthält. Das 
läßt sich aber durch die Properties Position bzw. Length lösen.

Alle anderen Lösungen mit Stream offen halten usw. sind Krampf, da man 
bei IDisposable-Objekten (also u.a. bei Streams) unbedingt dafür Sorge 
tragen muss, dass diese ordnungsgemäß Disposed werden. Das geht 
idealerweise so:
1
byte[] memoryBuffer;
2
long memoryBufferLength;
3
using (var memStream = new MemoryStream(...))
4
{
5
    ...
6
    // irgendwas mit memStream veranstalten
7
    ...
8
    memoryBuffer = memStream.GetBiffer();
9
    memoryBufferLength = memStream.Position; // wenn Position am Ende des Stream ist!
10
}
11
...
12
// hier kann man dann das Byte-Array weiterverarbeiten
13
// und z.B. einen neuen MemoryStream erzeugen
14
using(var memStream = new MemoryStream(memoryBuffer,0,memoryBufferLength))
15
{
16
    ...
17
}

Viel Erfolg!

Markus

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.