Ich habe einen Webserver, der große Binärdateien (mehrere Megabyte) in Byte-Arrays liest. Der Server kann mehrere Dateien gleichzeitig lesen (unterschiedliche Seitenanforderungen), daher suche ich nach der optimierten Methode, um dies zu tun, ohne die CPU zu stark zu belasten. Ist der folgende Code gut genug?
public byte[] FileToByteArray(string fileName)
{
byte[] buff = null;
FileStream fs = new FileStream(fileName,
FileMode.Open,
FileAccess.Read);
BinaryReader br = new BinaryReader(fs);
long numBytes = new FileInfo(fileName).Length;
buff = br.ReadBytes((int) numBytes);
return buff;
}
c#
.net
bytearray
binary-data
Tony_Henrich
quelle
quelle
byte[] buff = File.ReadAllBytes(fileName)
.Antworten:
Ersetzen Sie einfach das Ganze durch:
Wenn Sie jedoch über den Speicherverbrauch besorgt sind, sollten Sie nicht die gesamte Datei auf einmal in den Speicher einlesen. Sie sollten das in Stücken tun.
quelle
Ich könnte argumentieren, dass die Antwort hier im Allgemeinen "nicht" ist. Wenn Sie nicht unbedingt alle Daten auf einmal benötigen , sollten Sie eine
Stream
API (oder eine Variante von Reader / Iterator) verwenden. Dies ist besonders wichtig, wenn Sie mehrere parallele Vorgänge ausführen (wie in der Frage vorgeschlagen), um die Systemlast zu minimieren und den Durchsatz zu maximieren.Wenn Sie beispielsweise Daten an einen Anrufer streamen:
quelle
byte[]
aus irgendeinem Grund die gesamte Datei lesen müssen , sollten Sie keine Streams oder andere Elemente verwenden und nur die vom System bereitgestellte API verwenden.File.ReadAllBytes
.Ich würde das denken:
quelle
Ihr Code kann dies berücksichtigen (anstelle von File.ReadAllBytes):
Beachten Sie die Integer.MaxValue - Dateigrößenbeschränkung durch die Read-Methode. Mit anderen Worten, Sie können nur einen 2-GB-Block gleichzeitig lesen.
Beachten Sie auch, dass das letzte Argument für den FileStream eine Puffergröße ist.
Ich würde auch über das Lesen vorschlagen Filestream und BufferedStream .
Wie immer ist ein einfaches Beispielprogramm zum Profilieren, das am schnellsten ist, am vorteilhaftesten.
Auch Ihre zugrunde liegende Hardware hat einen großen Einfluss auf die Leistung. Verwenden Sie serverbasierte Festplatten mit großen Caches und eine RAID-Karte mit integriertem Speichercache? Oder verwenden Sie ein Standardlaufwerk, das an den IDE-Port angeschlossen ist?
quelle
var binaryReader = new BinaryReader(fs); fileData = binaryReader.ReadBytes((int)fs.Length);
in dieserusing
Aussage tun . Aber das ist effektiv so, wie es das OP getan hat. Ich habe nur eine Codezeile ausgeschnitten, indem ich auf Casting umgestellt habefs.Length
,int
anstatt denlong
Wert derFileInfo
Länge zu ermitteln und diesen zu konvertieren.Abhängig von der Häufigkeit der Vorgänge, der Größe der Dateien und der Anzahl der Dateien, die Sie betrachten, müssen andere Leistungsprobleme berücksichtigt werden. Eine Sache, an die Sie sich erinnern sollten, ist, dass jedes Ihrer Byte-Arrays dem Garbage Collector ausgeliefert wird. Wenn Sie keine dieser Daten zwischenspeichern, können Sie viel Müll verursachen und den größten Teil Ihrer Leistung an % Time in GC verlieren. Wenn die Chunks größer als 85 KB sind, werden Sie dem Large Object Heap (LOH) zugeordnet, für dessen Freigabe eine Sammlung aller Generationen erforderlich ist (dies ist sehr teuer und auf einem Server wird die gesamte Ausführung gestoppt, während sie ausgeführt wird ). Wenn Sie eine Menge Objekte auf dem LOH haben, kann dies zu einer LOH-Fragmentierung führen (das LOH wird niemals komprimiert), was zu einer schlechten Leistung und Ausnahmen aufgrund von Speichermangel führt. Sie können den Prozess recyceln, sobald Sie einen bestimmten Punkt erreicht haben, aber ich weiß nicht, ob dies eine bewährte Methode ist.
Der Punkt ist, dass Sie den gesamten Lebenszyklus Ihrer App berücksichtigen sollten, bevor Sie unbedingt alle Bytes auf die schnellstmögliche Weise in den Speicher einlesen. Andernfalls können Sie kurzfristige Leistung gegen Gesamtleistung eintauschen.
quelle
garbage collector
,chunks
, Leistung, Ereigniszähler , ...Ich würde sagen, es
BinaryReader
ist in Ordnung, kann aber dahingehend überarbeitet werden, anstatt all dieser Codezeilen, um die Länge des Puffers zu ermitteln:Sollte besser sein als zu verwenden
.ReadAllBytes()
, da ich in den Kommentaren zur Top-Antwort gesehen habe,.ReadAllBytes()
dass einer der Kommentatoren Probleme mit Dateien> 600 MB hatte, da aBinaryReader
für so etwas gedacht ist. Durch das Einfügen in eineusing
Erklärung wird auch sichergestellt, dass dieFileStream
undBinaryReader
geschlossen und entsorgt werden.quelle
new
dort nicht benötigt wurde. Entfernt.Wenn mit 'eine große Datei' jenseits der 4-GB-Grenze gemeint ist, ist meine folgende geschriebene Codelogik angemessen. Das wichtigste Problem ist der lange Datentyp, der mit der SEEK-Methode verwendet wird. Da ein LONG in der Lage ist, über 2 ^ 32 Datengrenzen hinaus zu zeigen. In diesem Beispiel verarbeitet der Code zuerst die große Datei in Blöcken von 1 GB. Nachdem die großen ganzen Blöcke von 1 GB verarbeitet wurden, werden die verbleibenden (<1 GB) Bytes verarbeitet. Ich verwende diesen Code bei der Berechnung des CRC von Dateien über die Größe von 4 GB hinaus. (Verwenden von https://crc32c.machinezoo.com/ für die crc32c-Berechnung in diesem Beispiel)
quelle
Verwenden Sie die BufferedStream-Klasse in C #, um die Leistung zu verbessern. Ein Puffer ist ein Block von Bytes im Speicher, der zum Zwischenspeichern von Daten verwendet wird, wodurch die Anzahl der Aufrufe des Betriebssystems verringert wird. Puffer verbessern die Lese- und Schreibleistung.
Im Folgenden finden Sie ein Codebeispiel und eine zusätzliche Erklärung: http://msdn.microsoft.com/en-us/library/system.io.bufferedstream.aspx
quelle
BufferedStream
wenn Sie das Ganze auf einmal lesen?benutze das:
quelle
Ich würde empfehlen, die
Response.TransferFile()
Methode dann aResponse.Flush()
undResponse.End()
für die Bereitstellung Ihrer großen Dateien zu versuchen .quelle
Wenn Sie mit Dateien über 2 GB arbeiten, werden Sie feststellen, dass die oben genannten Methoden fehlschlagen.
Es ist viel einfacher, den Stream einfach an MD5 zu übergeben und zuzulassen, dass Ihre Datei für Sie aufgeteilt wird:
quelle