Удалить первые 16 байт? - PullRequest
       12

Удалить первые 16 байт?

6 голосов
/ 28 марта 2010

Как мне удалить число байтов из массива байтов?

Ответы [ 4 ]

25 голосов
/ 28 марта 2010

РЕДАКТИРОВАТЬ: Как отмечается в комментарии nobugz (и в ответе Рида Копси), если вам на самом деле не нужен результат в виде байтового массива, вы должны использовать ArraySegment<T>:

ArraySegment<byte> segment = new ArraySegment<byte>(full, 16, full.Length - 16);

В противном случае будет необходимо копирование - массивы всегда имеют фиксированный размер, поэтому вы не можете «удалить» первые 16 байтов из существующего массива. Вместо этого вам придется создать новый меньший массив и скопировать в него соответствующие данные.

Предложение Зака ​​в правильном направлении для подхода без LINQ, но его можно упростить (предполагается, что вы уже знаете, что исходный массив имеет длину не менее 16 байт):

byte[] newArray = new byte[oldArray.Length - 16];
Buffer.BlockCopy(oldArray, 16, newArray, 0, newArray.Length);

или

byte[] newArray = new byte[oldArray.Length - 16];
Array.Copy(oldArray, 16, newArray, 0, newArray.Length);

Я подозреваю, Buffer.BlockCopy будет немного быстрее, но я точно не знаю.

Обратите внимание, что оба из них могут быть значительно более эффективными, чем подход LINQ, если задействованные массивы большие: подход LINQ требует, чтобы каждый байт был индивидуально возвращен из итератора, и потенциально промежуточные копии должны быть сделаны (таким же образом так как при добавлении элементов в List<T> необходимо периодически увеличивать резервный массив). Очевидно, что не оптимизируйте микро, но стоит проверить , если этот бит кода является узким местом производительности.

РЕДАКТИРОВАТЬ: я провел очень "быстрый и грязный" тест из трех подходов. Я не доверяю тестам, чтобы различать Buffer.BlockCopy и Array.Copy - они были довольно близки - но подход LINQ был более чем в 100 раз медленнее.

На моем ноутбуке, использующем байтовые массивы из 10 000 элементов, для выполнения 40000 копий с использованием LINQ потребовалось почти 10 секунд; вышеупомянутые подходы заняли около 80 мсек, чтобы выполнить тот же объем работы. Я увеличил количество итераций до 4 000 000, и это заняло всего около 7 секунд. Очевидно, что применяются обычные предостережения относительно микро-эталонов, но это довольно существенная разница.

Определенно используйте вышеуказанный подход, если он находится в пути кода, который важен для производительности:)

17 голосов
/ 28 марта 2010

Вы можете сделать это:

using System.Linq

// ...

var newArray = oldArray.Skip(numBytes).ToArray();
6 голосов
/ 28 марта 2010

Я также упомяну - в зависимости от того, как вы планируете использовать результаты, часто альтернативный подход заключается в использовании ArraySegment<T>, чтобы просто получить доступ к оставшейся части массива. Это исключает необходимость копирования массива, что может быть более эффективным в некоторых сценариях использования:

ArraySegment<byte> segment = new ArraySegment<byte>(originalArray, 16, originalArray.Length-16);

// Use segment how you'd use your array...  
0 голосов
/ 28 марта 2010

Если вы не можете использовать Linq, вы можете сделать это следующим образом:

byte[] myArray = // however you acquire the array

byte[] newArray = new byte[myArray.Length - 16];

for (int i = 0; i < newArray.Length; i++)
{
    newArray[i] = myArray[i + 16];
}

// newArray is now myArray minus the first 16 bytes

Вам также потребуется обработать случай, когда длина массива меньше 16 байт.

...