496 Stimmen

Beste Weg, um eine große Datei in ein Byte-Array in C# zu lesen?

Ich habe einen Webserver, der große Binärdateien (mehrere Megabyte) in Byte-Arrays liest. Der Server könnte mehrere Dateien gleichzeitig lesen (verschiedene Seitenanfragen), so dass ich auf der Suche nach dem optimierten Weg, dies zu tun, ohne die CPU zu sehr 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;
}

78 Stimmen

Ihr Beispiel kann wie folgt abgekürzt werden byte[] buff = File.ReadAllBytes(fileName) .

3 Stimmen

Warum bedeutet die Tatsache, dass es sich um einen Webservice eines Drittanbieters handelt, dass die Datei vollständig im RAM sein muss, bevor sie an den Webservice gesendet wird, und nicht gestreamt? Der Webservice wird den Unterschied nicht erkennen.

0 Stimmen

@Brian, Einige Clients wissen nicht, wie sie mit einem .NET-Stream umgehen sollen, wie zum Beispiel Java. Wenn dies der Fall ist, kann nur die gesamte Datei in einem Byte-Array gelesen werden.

10voto

Joel Punkte 300

Je nach Häufigkeit der Vorgänge, der Größe der Dateien und der Anzahl der Dateien, die Sie betrachten, gibt es weitere Leistungsaspekte zu berücksichtigen. Eine Sache, die Sie bedenken sollten, ist, dass jedes Ihrer Byte-Arrays dem Garbage Collector ausgeliefert ist. Wenn Sie die Daten nicht zwischenspeichern, könnten Sie am Ende eine Menge Müll erzeugen und einen Großteil Ihrer Leistung an % Zeit in GC . Wenn die Chunks größer als 85K sind, werden sie dem Large Object Heap (LOH) zugewiesen, der eine Sammlung aller Generationen erfordert, um sie freizugeben (dies ist sehr teuer und auf einem Server wird die gesamte Ausführung angehalten, während dies geschieht). Außerdem kann es bei einer großen Anzahl von Objekten im LOH zu einer Fragmentierung des LOH kommen (der LOH wird nie komprimiert), was zu einer schlechten Leistung und zu Ausnahmen bei Speicherplatzmangel führt. Sie können den Prozess ab einem bestimmten Punkt wiederverwenden, aber ich weiß nicht, ob das die beste Vorgehensweise ist.

Der Punkt ist, dass Sie den gesamten Lebenszyklus Ihrer Anwendung berücksichtigen sollten, bevor Sie unbedingt alle Bytes auf dem schnellstmöglichen Weg in den Speicher einlesen, da Sie sonst die kurzfristige Leistung gegen die Gesamtleistung eintauschen.

0 Stimmen

Quellcode C# darüber, für verwalten garbage collector , chunks , Leistung, Ereigniszähler , ...

2voto

Menno de Ruiter Punkte 23

Falls mit "eine große Datei" eine Datei jenseits der 4GB-Grenze gemeint ist, dann ist meine nachfolgend geschriebene Code-Logik angemessen. Der wichtigste Punkt ist der mit der SEEK-Methode verwendete LONG-Datentyp. Ein LONG ist in der Lage, über 2^32 Datengrenzen hinaus zu zeigen. In diesem Beispiel verarbeitet der Code zunächst die große Datei in 1-GB-Blöcken. Nachdem die großen 1-GB-Blöcke verarbeitet wurden, werden die restlichen (<1 GB) Bytes verarbeitet. Ich verwende diesen Code für die Berechnung des CRC von Dateien, die größer als 4 GB sind. (mit https://crc32c.machinezoo.com/ für die crc32c-Berechnung in diesem Beispiel)

private uint Crc32CAlgorithmBigCrc(string fileName)
{
    uint hash = 0;
    byte[] buffer = null;
    FileInfo fileInfo = new FileInfo(fileName);
    long fileLength = fileInfo.Length;
    int blockSize = 1024000000;
    decimal div = fileLength / blockSize;
    int blocks = (int)Math.Floor(div);
    int restBytes = (int)(fileLength - (blocks * blockSize));
    long offsetFile = 0;
    uint interHash = 0;
    Crc32CAlgorithm Crc32CAlgorithm = new Crc32CAlgorithm();
    bool firstBlock = true;
    using (FileStream fs = new FileStream(fileName, FileMode.Open, FileAccess.Read))
    {
        buffer = new byte[blockSize];
        using (BinaryReader br = new BinaryReader(fs))
        {
            while (blocks > 0)
            {
                blocks -= 1;
                fs.Seek(offsetFile, SeekOrigin.Begin);
                buffer = br.ReadBytes(blockSize);
                if (firstBlock)
                {
                    firstBlock = false;
                    interHash = Crc32CAlgorithm.Compute(buffer);
                    hash = interHash;
                }
                else
                {
                    hash = Crc32CAlgorithm.Append(interHash, buffer);
                }
                offsetFile += blockSize;
            }
            if (restBytes > 0)
            {
                Array.Resize(ref buffer, restBytes);
                fs.Seek(offsetFile, SeekOrigin.Begin);
                buffer = br.ReadBytes(restBytes);
                hash = Crc32CAlgorithm.Append(interHash, buffer);
            }
            buffer = null;
        }
    }
    //MessageBox.Show(hash.ToString());
    //MessageBox.Show(hash.ToString("X"));
    return hash;
}

2voto

Golden Lion Punkte 2590

Überblick: Wenn Ihr Bild als action= eingebettete Ressource hinzugefügt wird, verwenden Sie GetExecutingAssembly, um die jpg-Ressource in einen Stream zu laden, und lesen Sie dann die binären Daten im Stream in ein Byte-Array

   public byte[] GetAImage()
    {
        byte[] bytes=null;
        var assembly = Assembly.GetExecutingAssembly();
        var resourceName = "MYWebApi.Images.X_my_image.jpg";

        using (Stream stream = assembly.GetManifestResourceStream(resourceName))
        {
            bytes = new byte[stream.Length];
            stream.Read(bytes, 0, (int)stream.Length);
        }
        return bytes;

    }

0voto

Todd Moses Punkte 10879

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 an das Betriebssystem verringert wird. Puffer verbessern die Lese- und Schreibleistung.

Im Folgenden finden Sie ein Codebeispiel und weitere Erläuterungen: http://msdn.microsoft.com/en-us/library/system.io.bufferedstream.aspx

0 Stimmen

Welchen Sinn hat die Verwendung einer BufferedStream wenn man das Ganze auf einmal liest?

0 Stimmen

Er bat darum, die Datei möglichst nicht auf einmal zu lesen.

9 Stimmen

Leistung ist im Rahmen einer Operation messbar. Ein zusätzlicher Puffer für einen Datenstrom, der sequentiell und gleichzeitig in den Speicher eingelesen wird, wird wahrscheinlich nicht von einem zusätzlichen Puffer profitieren.

0voto

Disha Sharma Punkte 11

Dies verwenden:

 bytesRead = responseStream.ReadAsync(buffer, 0, Length).Result;

2 Stimmen

Willkommen bei Stack Overflow! Da Erklärungen ein wichtiger Teil der Antworten auf dieser Plattform sind, erklären Sie bitte Ihren Code und wie er das Problem in der Frage löst und warum er besser als andere Antworten sein könnte. Unser Leitfaden Wie man eine gute Antwort schreibt könnte für Sie hilfreich sein. Danke

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X