Подтвердить что ты не робот

Добавьте два или более байтовых массива в С#

Есть ли лучший способ (см. ниже) добавить два байтовых массива в С#?

Притворяясь, что у меня есть полный контроль, я могу сделать первый массив байтов достаточно большим для хранения второго массива байтов в конце и использовать Array.CopyTo. Или я могу перебрать отдельные байты и выполнить назначение.

Есть ли лучшие способы? Я не могу себе представить, что вы делаете что-то вроде преобразования массивов байтов в строку и их присоединения, а их преобразование будет лучше, чем любой из вышеперечисленных методов.

С точки зрения лучшего/лучшего (по порядку):

  • Fastest
  • Максимальное потребление оперативной памяти

Ограничение состоит в том, что я должен работать в среде .NET 2.0.

Рекомендуются два варианта: MemoryStream и BlockCopy. Я пропустил простой тест скорости 10 000 000 циклов 3 раза и получил следующие результаты:

Среднее значение 3 пробега 10 000 000 циклов в миллисекундах:

  • BlockCopy Time: 1154, с диапазоном в 13 миллисекунд
  • MemoryStream GetBuffer Время: 1470, с диапазоном в 14 миллисекунд
  • MemoryStream ToArray Время: 1895, с диапазоном 3 миллисекунды
  • CopyTo Time: 2079, с диапазоном в 19 миллисекунд
  • Байт по байтам Время: 2203, с диапазоном 10 миллисекунд

Результаты списка <byte> AddRange более 10 миллионов циклов: Список <byte> Время: 16694

Относительное потребление ОЗУ (1 - базовое, более высокое):

  • Байт по байтам: 1
  • BlockCopy: 1
  • Копировать в: 1
  • MemoryStream GetBuffer: 2.3
  • MemoryStream ToArray: 3.3
  • Список <byte> : 4.2

Тест показывает, что в общем случае, если вы не делаете много копий байта [ , которые я], просмотр байтовых копий не стоит особого внимания (например, 10 миллионов запусков дают разницу в 1,1 секунды].

4b9b3361

Ответ 2

Создайте новый MemoryStream, передав в конструктор буфер, который точно совпадает с размером объединенного. Напишите отдельные массивы, а затем, наконец, используйте буфер:

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();

Многие низкоуровневые функции ввода/вывода в .NET берут байтовые массивы и смещения. Это было сделано для предотвращения ненужных копий. Убедитесь, что вам действительно нужен объединенный массив, если он чувствителен к производительности, иначе просто используйте буферы и смещения.

Ответ 3

Вы также можете использовать подход с MemoryStream. Предположим, что b1 и b2 - это два байтовых массива, вы можете получить новый, b3, используя MemoryStream следующим образом:

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

Это должно работать без LINQ и на самом деле довольно быстро.

Ответ 4

Другой вариант, хотя я не тестировал его, чтобы увидеть, как он работает с точки зрения скорости и потребления памяти, будет ли подход LINQ:

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

... где bytesOne, bytesTwo и bytesThree - массивы байтов. Поскольку Concat использует отложенное выполнение, это не должно создавать промежуточные массивы и не должно дублировать исходные массивы до тех пор, пока они не конструируют окончательный объединенный массив в конце.

Изменить: LINQBridge позволит вам использовать LINQ-to-Objects (это пример) в фреймворке 2.0. Я понимаю, если вы не хотите зависеть от этого, но это вариант.

Ответ 5

Если у вас есть массивы, размер которых будет меняться время от времени, вам, вероятно, лучше использовать List<T> в первую очередь. Затем вы можете просто вызвать метод AddRange() списка.

В противном случае Array.Copy() или Array.CopyTo() будут такими же хорошими, как и все, что вы, вероятно, увидите.

Ответ 6

Вы учили использовать List или ArrayList вместо массива? С этими типами они могут расти или сжиматься и добавлять через InsertRange

Ответ 7

Вам нужен вывод для фактического байтового массива?

Если нет, вы можете создать себе "умный курсор" (что похоже на то, что делает LINQ): создать пользовательский IEnumerator <byte> который сначала перебирает первый массив, а просто продолжит второй, без перерыва.

Это будет работать в среде 2.0 быстро (в том, что объединение массивов практически не требует затрат), и не используйте больше RAM, чем массивы уже потребляют.

Ответ 8

Ваша первая возможность сделать первый массив достаточно большим, чтобы содержать второй массив, и использование Array.CopyTo заканчивается примерно таким же, как ручное повторение каждого элемента и выполнение задания. Array.CopyTo() просто делает его более кратким.

Преобразование в строку и обратно в массив будет ужасно медленным, в отличие от вышеизложенного. И, скорее всего, будет использовать больше памяти.