web-dev-qa-db-fra.com

Ajouter deux tableaux d'octets ou plus en C #

Existe-t-il une meilleure façon (voir ci-dessous) d'ajouter des tableaux de deux octets en C #?

En faisant semblant d'avoir un contrôle complet, je peux rendre le premier tableau d'octets suffisamment grand pour contenir le second tableau d'octets à la fin et utiliser la fonction Array.CopyTo . Ou je peux boucler sur des octets individuels et faire une affectation.

Y a-t-il de meilleures façons? Je ne peux pas imaginer faire quelque chose comme convertir les tableaux d'octets en chaîne et les joindre et les reconvertir serait mieux que l'une ou l'autre méthode ci-dessus.

En termes de meilleur/meilleur (dans l'ordre):

  1. Le plus rapide
  2. Moins RAM consommation

Une contrainte est que je dois travailler dans le framework .NET 2.0.

Les deux choix recommandés sont MemoryStream et BlockCopy. J'ai exécuté un test de vitesse simple de 10 000 000 boucles 3 fois et j'ai obtenu les résultats suivants:

Moyenne de 3 exécutions de 10 000 000 de boucles en millisecondes:

  • BlockCopy Time: 1154 , avec une plage de 13 millisecondes
  • MemoryStream GetBuffer Time: 1470, avec une plage de 14 millisecondes
  • MemoryStream ToArray Time: 1895, avec une plage de 3 millisecondes
  • CopyTo Time: 2079, avec une plage de 19 millisecondes
  • Temps octet par octet: 2203, avec une plage de 10 millisecondes

Résultats de la liste <byte> AddRange plus de 10 millions de boucles: List <byte> Durée: 16694

Relative RAM Consommation (1 est la ligne de base, plus haut est pire):

  • Octet par octet: 1
  • BlockCopy: 1
  • Copier vers: 1
  • MemoryStream GetBuffer: 2.3
  • MemoryStream ToArray: 3.3
  • Liste <octet>: 4.2

Le test montre qu'en général, à moins que vous ne fassiez beaucoup de copies d'octets [ que je suis ], regarder des copies d'octets ne vaut pas la peine d'être ciblé [ par exemple 10 millions d'exécutions, ce qui représente une différence pouvant atteindre 1,1 seconde].

30
torial

Vous voulez BlockCopy

Selon ce billet de blog c'est plus rapide que Array.CopyTo.

24
dss539

Vous pouvez également utiliser une approche avec un MemoryStream. Supposons que b1 et b2 soient des tableaux à deux octets, vous pouvez en obtenir un nouveau, b3, en utilisant le MemoryStream de la manière suivante:

var s = new MemoryStream();
s.Write(b1, 0, b1.Length);
s.Write(b2, 0, b2.Length);
var b3 = s.ToArray();

Cela devrait fonctionner sans LINQ et est en fait un peu plus rapide.

14
flq

Créez un nouveau MemoryStream en passant dans le constructeur un tampon qui est exactement la taille de celui fusionné. Écrivez les tableaux individuels, puis utilisez enfin le tampon:

byte[] deadBeef = new byte[] { 0xDE, 0xAD, 0xBE, 0xEF};
byte[] baadF00d = new byte[] { 0xBA, 0xAD, 0xF0, 0x0D};
int newSize = deadBeef.Length + baadF00d.Length;
var ms = new MemoryStream(new byte[newSize], 0, newSize, true, true);
ms.Write(deadBeef, 0, deadBeef.Length);
ms.Write(baadF00d, 0, baadF00d.Length);
byte[] merged = ms.GetBuffer();

De nombreuses fonctions d'E/S de bas niveau dans .NET prennent des tableaux d'octets et des décalages. Cela a été fait pour éviter les copies inutiles. Assurez-vous que vous avez vraiment besoin du tableau fusionné si cela est sensible aux performances, sinon utilisez simplement des tampons et des décalages.

11
Jeff Moser

Une autre option, même si je ne l'ai pas testée pour voir comment elle se porte en termes de vitesse et de consommation de mémoire, serait l'approche LINQ:

byte[] combined = bytesOne.Concat(bytesTwo).Concat(bytesThree).ToArray();

... où bytesOne, bytesTwo et bytesThree sont des tableaux d'octets. Étant donné que Concat utilise une exécution différée, cela ne doit pas créer de tableaux intermédiaires et ne doit pas dupliquer les tableaux d'origine jusqu'à ce qu'il construise le tableau fusionné final à la fin.

Edit: LINQBridge vous permettra d'utiliser LINQ-to-Objects (dont ceci est un exemple) dans le framework 2.0. Je comprends si vous ne voulez pas en dépendre, mais c'est une option.

6
Joel Mueller

Si vous avez des tableaux dont la taille changera de temps en temps, vous feriez probablement mieux d'utiliser un List<T> En premier lieu. Ensuite, vous pouvez simplement appeler la méthode AddRange() de la liste.

Sinon, Array.Copy () ou Array.CopyTo () sont aussi bons que tout ce que vous verrez probablement.

3
Joel Coehoorn

Avez-vous besoin que la sortie soit réellement un tableau d'octets?

Sinon, vous pouvez créer vous-même un "curseur intelligent" (qui est similaire à ce que fait LINQ): créez un IEnumerator personnalisé <octet> qui itérera d'abord le premier tableau, et continuera simplement sur le second sans interruption.

Cela fonctionnerait dans le cadre 2.0 serait rapide (en ce que la jonction des tableaux n'a pratiquement aucun coût), et n'utiliserait pas plus RAM que les tableaux consomment déjà.

2
Arjan Einbu

Avez-vous appris à utiliser List ou ArrayList au lieu d'un tableau? Avec ces types, ils peuvent s'agrandir ou se réduire et s'ajouter via InsertRange

2
AndrewB

Votre première option consistant à créer le premier tableau suffisamment grand pour contenir le deuxième tableau et à utiliser Array.CopyTo finit par être à peu près la même que d'itérer manuellement sur chaque élément et de faire l'affectation. Array.CopyTo () le rend simplement plus concis.

La conversion en chaîne et retour en tableau sera horriblement lente contrairement à ce qui précède. Et utiliserait probablement plus de mémoire.

0
Nate