Comment écrire des super-rapide de fichiers de streaming de code en C#?
Je dois diviser un énorme fichier en plusieurs fichiers plus petits. Chacun des fichiers de destination est défini par un décalage et la longueur est le nombre d'octets. Je suis en utilisant le code suivant:
private void copy(string srcFile, string dstFile, int offset, int length)
{
BinaryReader reader = new BinaryReader(File.OpenRead(srcFile));
reader.BaseStream.Seek(offset, SeekOrigin.Begin);
byte[] buffer = reader.ReadBytes(length);
BinaryWriter writer = new BinaryWriter(File.OpenWrite(dstFile));
writer.Write(buffer);
}
Considérant que j'ai appeler cette fonction à environ 100 000 fois, il est extrêmement lente.
- Est-il un moyen de faire de l'Écrivain connecté directement au Lecteur? (Qui est, sans charger le contenu dans la mémoire Tampon dans la mémoire).
- Fichier.OpenRead et Fichier.OpenWrite de 100 000 sera lente bien...
- Êtes-vous le fractionnement du fichier parfaitement, c'est à dire pourriez-vous reconstruire un fichier volumineux par juste de rejoindre tous les petits fichiers? Si donc il y a des économies à avoir là. Si non, les gammes de petits fichiers se chevauchent? Ils sont triés dans l'ordre de décalage?
Vous devez vous connecter pour publier un commentaire.
Je ne crois pas qu'il y ait quelque chose à l'intérieur .NET pour permettre la copie d'une section d'un fichier sans mise en mémoire tampon en mémoire. Cependant, il me semble que c'est inefficace de toute façon, comme il a besoin pour ouvrir le fichier d'entrée et de chercher de nombreuses fois. Si vous êtes juste de scinder le fichier, pourquoi ne pas ouvrir le fichier d'entrée une fois, et puis il suffit d'écrire quelque chose comme:
Cela a un mineur de l'inefficacité dans la création d'un tampon à chaque invocation - vous pouvez créer le tampon une fois et le passer dans la méthode ainsi:
Noter que cette ferme également le flux de sortie (en raison de l'utilisation de déclaration) que votre code d'origine n'a pas.
Le point important est que cela permettra d'utiliser le système d'exploitation du fichier de mise en mémoire tampon de manière plus efficace, parce que vous réutilisez le même flux d'entrée, au lieu de rouvrir le fichier au début et puis en cherchant.
Je pense il va être beaucoup plus rapide, mais évidemment, vous aurez besoin de l'essayer pour voir...
Cela suppose contiguë morceaux, bien sûr. Si vous avez besoin d'ignorer les bits du fichier, vous pouvez le faire à partir de l'extérieur de la méthode. Aussi, si vous écrivez des fichiers de très petite taille, vous pouvez optimiser pour que la situation de trop - la meilleure façon de le faire serait probablement à introduire un
BufferedStream
enveloppant le flux d'entrée.Math.Min
avant d'entrer dans la boucle? Ou mieux encore, à supprimer le paramètre de durée, car il peut être calculée au moyen de la mémoire tampon? Désolé d'être pointilleux et nécro ce! Merci à l'avance.Le moyen le plus rapide pour faire des e/S de fichier à partir de C# est d'utiliser le Windows ReadFile et WriteFile fonctions. J'ai écrit une classe C# qui encapsule cette capacité ainsi que d'un programme d'étalonnage qui regarde provenant de plusieurs méthodes d'e/S, y compris BinaryReader et BinaryWriter. Voir mon billet de blog à:
http://designingefficientsoftware.wordpress.com/2011/03/03/efficient-file-io-from-csharp/
Quelle est la taille de
length
? Vous pouvez faire mieux ré-utiliser un fixe de taille moyenne (d'assez grande taille, mais pas obscène) de la mémoire tampon, et d'oublierBinaryReader
... il suffit d'utiliserStream.Read
etStream.Write
.(edit) quelque chose comme:
Vous ne devriez pas ré-ouvrir le fichier source à chaque fois que vous faites un copier, mieux de l'ouvrir une fois et de passer l'résultant BinaryReader à la fonction de copie. Aussi, il pourrait aider si vous commandez votre cherche, afin de ne pas faire de grands sauts à l'intérieur du fichier.
Si les longueurs ne sont pas trop gros, vous pouvez également essayer de regrouper plusieurs copie des appels par le groupement des décalages qui se trouvent à proximité les uns des autres et de la lecture de l'ensemble du bloc dont vous avez besoin pour eux, par exemple:
peuvent être regroupées de manière à lire:
Vous n'avez alors qu'à "chercher" dans votre tampon et peut écrire les trois nouveaux fichiers à partir de là sans avoir à lire de nouveau.
Avez-vous considéré l'utilisation de la CCR depuis que vous êtes à l'écriture dans des fichiers séparés, vous pouvez tout faire en parallèle (lecture et écriture) et la CCR, il est très facile à faire.
Ce code des postes de compensations pour un port CCR qui provoque un Thread à être créé pour exécuter le code dans la méthode de Fractionnement. Ce qui vous fait ouvrir le fichier plusieurs fois, mais se débarrasser de la nécessité pour la synchronisation. Vous pouvez la rendre plus efficace en terme de mémoire, mais vous aurez à sacrifier la vitesse.
La première chose que je recommande est de prendre des mesures. Où en êtes-vous perdre votre temps? Est-il dans la lecture ou l'écriture?
Plus de 100 000 accès (somme pour l'époque):
Comment beaucoup de temps est consacré à l'allocation de la mémoire tampon de tableau?
Comment beaucoup de temps est consacré à l'ouverture du fichier pour le lire (c'est le même fichier à chaque fois?)
Comment beaucoup de temps est passé dans les opérations de lecture et écriture?
Si vous ne faites pas n'importe quel type de transformation sur le fichier, vous avez besoin d'un BinaryWriter, ou vous pouvez utiliser un filestream pour l'écrit? (essayez, vous obtenez l'identique de sortie? ne fait-il gagner du temps?)
À l'aide de FileStream + StreamWriter je sais que c'est possible de créer des fichiers en peu de temps (moins de 1 min 30 secondes). J'ai créer trois fichiers totalisant plus de 700 méga-octets d'un fichier à l'aide de cette technique.
Votre principal problème avec le code que vous utilisez est que vous ouvrez un fichier à chaque fois. C'est la création d'un fichier I/O frais généraux.
Si vous connaissait les noms des fichiers que vous serait de générer à l'avance, vous pouvez extraire le Fichier.OpenWrite dans une méthode distincte; il va augmenter la vitesse. Sans voir le code qui détermine la façon dont vous êtes fractionner les fichiers, je ne pense pas que vous pouvez obtenir beaucoup plus rapide.
Personne ne suggère threading? L'écriture de petits fichiers ressemble livre de texte exemple de l'endroit où les fils sont utiles. Configurer un tas de fils pour créer des fichiers plus petits. de cette façon, vous pouvez créer toutes en même temps et vous n'avez pas besoin d'attendre pour que chacun se terminer. Mon hypothèse est que la création des fichiers(disque de l'opération) prendra beaucoup plus de temps que de diviser les données. et bien sûr, vous devez vérifier d'abord qu'une approche séquentielle n'est pas adéquate.
(Pour référence future.)
Peut-être la façon la plus rapide de le faire serait d'utiliser les fichiers mappés en mémoire (principalement de la copie de la mémoire et de l'OS de la manipulation du fichier de lit/écrit par l'intermédiaire de sa pagination/gestion de la mémoire).
Les fichiers Mappés en mémoire sont pris en charge dans du code managé dans .NET 4.0.
Mais comme indiqué, vous avez besoin de profil et attendre pour passer en code natif pour des performances maximales.