Laden...

Schreiben eines Streams in ein Byte-Array mit Stream-Length

Erstellt von ThomasE. vor 2 Jahren Letzter Beitrag vor 2 Jahren 433 Views
T
ThomasE. Themenstarter:in
461 Beiträge seit 2013
vor 2 Jahren
Schreiben eines Streams in ein Byte-Array mit Stream-Length

Hallo liebe Community,

ich stecke momentan in einer Glaubenskrise bzw. hab ich derzeit einen Knoten im Gehirn...

Eine ganz einfache Sache, einen Stream in ein byte-Array stecken.
Weiß nicht wieso mir das bis jetzt nie gestört hat, hier ein Beispiel:


                using (Stream stream = this._FileService.GetFileConverted(this.ConnectionId, documentId, versionId, null, null, null, targetFormat, addAnnotations, addOverlay, contentType))
                {
                    byte[] bytes = new byte[stream.Length];
                    int numBytesToRead = (int)stream.Length;
                    int numBytesRead = 0;
                    while (numBytesToRead > 0)
                    {
                        int n = stream.Read(bytes, numBytesRead, numBytesToRead);
                        if (n == 0) break;
                        numBytesRead += n;
                        numBytesToRead -= n;
                    }
                    return bytes;
                }

stream.Length ist ja vom Typ long.
Die restlichen Variablen und gefordeten Parameter in int.

Mir ist klar, dass _stream.Length _die gesamte Länge des Streams ist und die Angaben bei _numBytesToRead _und _numBytesRead _nur der Offset und die Buffergröße.
Habe das Beispiel von Microsoft:
FileStream.Read Method (System.IO)

Mich stört, dass zunächst _numBytesToRead _das stream.Length reingeboxt bekommt, also unter Umständen gekürzt wird.
Im _while _wird der gelesene Buffer _n _von dem _numBytesToRead _aber abgezogen.

Das kann sich ja irgendwie nicht ausgehen oder?

Ich habe den Titel mal angepasst, so dass Suchende auch etwas damit anfangen können. EDIT: Ich sollte beim Wort "Shift" im Titel das "f" nicht vergessen... 😄

T
2.224 Beiträge seit 2008
vor 2 Jahren

Das Beispiel soll eigentlich nur die Nutzung von Read illustrieren.
Bei Dateien ab 2,4 GB Größe würde das Beispiel die Datei abschneiden, dass stimmt schon.
Hier kannst du gerne einen Fehler melden, falls dich das stört.

Ansonsten würde ich den Stream nie so verarbeiten.
Hier sollte man solange Read aufrufen, bis der Wert ≤ 0 geliefert wird.
Dann ist man am Ende des Streams angekommen egal wie lange dieser war.

Die Length kann man z.B. verwenden um bei kleinen Dateien ein Array zu erstellen und die Daten in einem Rutsch zu lesen oder um eine Art Progress anzuzeigen.
Dabei muss man aber beachten, dass dieser u.U. nicht immer direkt zur Verfügung steht.
Bei einer lokalen Datei ist das kein Problem, bei einem Stream z.B. über http hingegen muss erst ein Read erfolgen.

T-Virus

Developer, Developer, Developer, Developer....

99 little bugs in the code, 99 little bugs. Take one down, patch it around, 117 little bugs in the code.

2.080 Beiträge seit 2012
vor 2 Jahren

Oder - wenn das Ziel ein byte-Array ist: MemoryStream

Nimm einen MemoryStream (und gib beim Konstruktor ggf. die Länge mit), kopiere alles vom Quell-Stream in den MemoryStream (CopyTo) und hole dir anschließend dein Array (ToArray).
Dein Vorhaben ist also schon fertig, Du musst es nur noch nutzen ^^

Aber ja, auch da wird abgeschnitten, das ist halt so.
So viel willst Du aber auch nicht im RAM haben, damit hast Du ganz schnell Performance-Probleme.
Besser wäre, Du verarbeitest die Daten als Stream, also Stück für Stück und hast dann nur das im RAM, was Du gerade brauchst.

By the way:
Eine Methode mit 10 Parametern, von denen auch noch 3 null sind, deutet auf ein Problem hin 😉
Eine Methode, die so viele Parameter braucht, von denen auch noch einige optional sind, macht meist mehr, als sie sollte.

NuGet Packages im Code auslesen
lock Alternative für async/await

Beim CleanCode zählen nicht die Regeln, sondern dass wir uns mit diesen Regeln befassen, selbst wenn wir sie nicht befolgen - hoffentlich nach reiflichen Überlegungen.

16.842 Beiträge seit 2008
vor 2 Jahren

Erklär mal Deinen tatsächlichen Use Case. Mittlerweile, mit .NET 5/6 gibts neue, bessere Lösungen, die zB. auf Span<T> basieren.
Du hast die Docs auf .NET 4.6 verlinkt - mit was arbeitest Du überhaupt?

Anhand der Signatur der Methode, wie es auch Palladin angedeutet hat, vermute ich auch, dass evtl. die Herangehensweise schon suboptimal ist.
Davon abgesehen ist das ein Beispiel aus der Dateiverarbeitung, die sicherlich so nicht überall, wo Streams verwendet werden, sinn macht oder gut wäre.

6.911 Beiträge seit 2009
vor 2 Jahren

Hallo,

Ansonsten würde ich den Stream nie so verarbeiten.
...
Die Length kann man z.B. verwenden um bei kleinen Dateien ein Array zu erstellen und die Daten in einem Rutsch zu lesen...
...
Bei einer lokalen Datei ist das kein Problem, bei einem Stream z.B. über http hingegen muss erst ein Read erfolgen.

Da stimm ich zu 🙂
V.a. für Streams "unbekanner" Größe ist I/O pipelines - .NET sehr empfehlenswert.

mfG Gü

Stellt fachliche Fragen bitte im Forum, damit von den Antworten alle profitieren. Daher beantworte ich solche Fragen nicht per PM.

"Alle sagten, das geht nicht! Dann kam einer, der wusste das nicht - und hat's gemacht!"

T
ThomasE. Themenstarter:in
461 Beiträge seit 2013
vor 2 Jahren

Hallo zusammen, danke mal für Eure Antworten.

Ein wenig zum Hintergrund:
Es ist eine Änderung im alten Source, der basiert auf dem Framework 4.6.2 und das ändert sich auch nicht mehr.
Die Methode die aufgerufen wird ist noch eine WCF Methode, da habe ich keinen Einfluß drauf.
Die 'null' Parameter sind optionale, um das Dokument in einer bestimmten Version zu holen oder so ähnliches, also nichts tragisches.
Es gibt in der WCF Schnittstelle nur diese eine Methode, um eine Datei mit Annotationen zu erhalten. Das ist auch der Grund der Änderung/Erweiterung.
Den Service den ich verwende ist schon ein fertiger Proxy für die WCF Anbindung. Ebenfalls keinen Einfluß drauf.
Der Rückgabewert ist ein Stream, also die abstrakte Basisklasse. Weiß aber das von der WCF Schnittstelle ein Filestream übergeben wird.

Die Dateien um die es hier geht sind in der Regel nicht größer als 2MB, wollte mich damit aber nicht zufrieden geben.
Sah in die Doku und war verwirrt 😉

Aber ich denke ich habe schon verstanden und lag auch bei meiner Verwirrung da wohl nicht ganz falsch.

Die bessere Lösung ist sicher paketchenweise zu lesen und gleich auf die Platte zu schreiben, eben auch wegen dem RAM.
Obwohl es immer nur 1 Datei ist, ist es vom Logischen her einfach besser umgesetzt.

Die Lösung gibt es schon, hole eine Datei und schicke sie mit anderen Parametern zu einem anderen Verarbeitungssystem.
Der Unterschied um das es hier jetzt geht, es sollen die Annotationen mit exportiert werden als fixer Bestandteil des Dokuments.
Die andere vorhandene Methode hat es etwas einfacher, die bekommt gleich ein byte Array und keinen Stream.

Ich habe den Titel mal angepasst, so dass Suchende auch etwas damit anfangen können. EDIT: Ich sollte beim Wort "Shift" im Titel das "f" nicht vergessen... 😄

2.080 Beiträge seit 2012
vor 2 Jahren

Wenn Du einen bestehenden Stream auf die Platte schreiben willst, dann mach einfach den FileStream auf und nutze hier das CopyTo, das gibt's für 4.6.2 "schon".
Das beachtet dann auch das blockweise kopieren, kannst Du dort nachlesen: https://referencesource.microsoft.com/#mscorlib/system/io/stream.cs,295ec16c77d4fafb
Die Methode interessiert sich auch nicht für den Quell- und Ziel-Stream, es geht mit jedem Stream.

NuGet Packages im Code auslesen
lock Alternative für async/await

Beim CleanCode zählen nicht die Regeln, sondern dass wir uns mit diesen Regeln befassen, selbst wenn wir sie nicht befolgen - hoffentlich nach reiflichen Überlegungen.

16.842 Beiträge seit 2008
vor 2 Jahren

Die bessere Lösung ist sicher paketchenweise zu lesen und gleich auf die Platte zu schreiben, eben auch wegen dem RAM.
Obwohl es immer nur 1 Datei ist, ist es vom Logischen her einfach besser umgesetzt.

Das kommt drauf an.

Parallel IO to Disk ist auch ein Angriffsszenario (DOS), da nicht jede Festplatte mit parallelen Schreibarbeiten zurecht kommt. Damit kann man (in der Theorie) Systeme gezielt überlasten.
Es gibt daher durchaus legitime Fälle für eine Pipelining eines solchen Szenarios (zB SMB), weil das auch die Performance bei der Übertragung steigern kann.

2.080 Beiträge seit 2012
vor 2 Jahren

Parallel IO to Disk ist auch ein Angriffsszenario (DOS), da nicht jede Festplatte mit parallelen Schreibarbeiten zurecht kommt.

Ich glaube nicht, dass er paralleles schreiben meint, sondern eher genau das, was CopyTo macht: Einen Block lesen, schreiben, lesen, schreiben, ...

NuGet Packages im Code auslesen
lock Alternative für async/await

Beim CleanCode zählen nicht die Regeln, sondern dass wir uns mit diesen Regeln befassen, selbst wenn wir sie nicht befolgen - hoffentlich nach reiflichen Überlegungen.

T
ThomasE. Themenstarter:in
461 Beiträge seit 2013
vor 2 Jahren

Ich denke er meint, wenn die Funktion parallel öfters aufgerufen wird, dass es da zu Problemen kommen kann und nicht die Logik in der Methode ansich.

Hinweis von Abt vor 2 Jahren

Bitte keine Full Quotes

Ich habe den Titel mal angepasst, so dass Suchende auch etwas damit anfangen können. EDIT: Ich sollte beim Wort "Shift" im Titel das "f" nicht vergessen... 😄