[C#] La meilleure façon de lire un gros fichier dans un tableau d'octets en C #?


Answers

Je pourrais faire valoir que la réponse ici est généralement "ne pas". À moins d' avoir absolument besoin de toutes les données à la fois, pensez à utiliser une API basée sur les Stream (ou une variante de lecteur / itérateur). Ceci est particulièrement important lorsque vous avez plusieurs opérations en parallèle (comme suggéré par la question) pour minimiser la charge du système et maximiser le débit.

Par exemple, si vous diffusez des données à un appelant:

Stream dest = ...
using(Stream source = File.OpenRead(path)) {
    byte[] buffer = new byte[2048];
    int bytesRead;
    while((bytesRead = source.Read(buffer, 0, buffer.Length)) > 0) {
        dest.Write(buffer, 0, bytesRead);
    }
}
Question

J'ai un serveur Web qui lira de gros fichiers binaires (plusieurs mégaoctets) dans des tableaux d'octets. Le serveur pourrait lire plusieurs fichiers en même temps (demandes de pages différentes), donc je suis à la recherche de la manière la plus optimisée de le faire sans trop taxer le CPU. Le code ci-dessous est-il assez bon?

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;
}



Votre code peut être factorisé à ceci (au lieu de File.ReadAllBytes):

public byte[] ReadAllBytes(string fileName)
{
    byte[] buffer = null;
    using (FileStream fs = new FileStream(fileName, FileMode.Open, FileAccess.Read))
    {
        buffer = new byte[fs.Length];
        fs.Read(buffer, 0, (int)fs.Length);
    }
    return buffer;
} 

Notez Integer.MaxValue - limitation de taille de fichier placée par la méthode Read. En d'autres termes, vous ne pouvez lire qu'un bloc de 2 Go à la fois.

Notez également que le dernier argument de FileStream est une taille de tampon.

Je suggère également de lire sur FileStream et BufferedStream .

Comme toujours, un simple exemple de programme à profiler le plus rapide sera le plus bénéfique.

Votre matériel sous-jacent aura également un effet important sur les performances. Utilisez-vous des disques durs basés sur un serveur avec des caches volumineux et une carte RAID avec un cache mémoire intégré? Ou utilisez-vous un lecteur standard connecté au port IDE?




Je dirais que BinaryReader est bien, mais peut être refactorisé à ceci, au lieu de toutes ces lignes de code pour obtenir la longueur du tampon:

public byte[] FileToByteArray(string fileName)
{
    byte[] fileData = null;

    using (FileStream fs = File.OpenRead(fileName)) 
    { 
        using (BinaryReader binaryReader = new BinaryReader(fs))
        {
            fileData = binaryReader.ReadBytes((int)fs.Length); 
        }
    }
    return fileData;
}

Devrait être mieux que d'utiliser .ReadAllBytes() , puisque j'ai vu dans les commentaires sur la réponse supérieure qui inclut .ReadAllBytes() que l'un des commentateurs avait des problèmes avec les fichiers> 600 Mo, car un BinaryReader est destiné à ce genre de chose. En outre, le placer dans une instruction using garantit que FileStream et BinaryReader sont fermés et éliminés.




Je recommanderais d'essayer la méthode Response.TransferFile() puis un Response.Flush() et Response.End() pour servir vos fichiers volumineux.