C #: массив байтов Concat [дубликат]

Это означает, что вы пытаетесь манипулировать тем, что имеет ссылку, но еще не инициализировано. Первое, что нужно сделать, это проверить каждый созданный экземпляр. Используйте контрольные точки, часы, проверяйте свои значения varibale. Следить за трассировкой стека и искать точные строки и столбцы, которые создают проблему

201
задан casperOne 26 May 2011 в 18:49
поделиться

12 ответов

Для примитивных типов (включая байты) используйте System.Buffer.BlockCopy вместо System.Array.Copy. Это быстрее.

Я назначил каждый из предложенных методов в цикле, выполненном 1 миллион раз, используя 3 массива по 10 байт каждый. Вот результаты:

  1. Новый байт-массив с использованием System.Array.Copy - 0.2187556 секунд
  2. Новый байт-массив с использованием System.Buffer.BlockCopy - 0.1406286 секунд
  3. IEnumerable & lt ; byte> с использованием оператора C # yield - 0.0781270 секунд
  4. IEnumerable & lt; byte> с использованием Concact & lt;> - 0.0781270 секунд LINQ

Я увеличил размер каждого массива до 100 элементов и повторно запустить тест:

  1. Новый массив байтов с использованием System.Array.Copy - 0.2812554 секунд
  2. Новый байт-массив с использованием System.Buffer.BlockCopy - 0.2500048 секунд
  3. IEnumerable & lt; byte> с использованием оператора C # yield - 0.0625012 секунд
  4. IEnumerable & lt; byte> с использованием Concact & lt;> - 0.0781265 секунд LINQ

Я увеличил размер каждого массива до 1000 элементов и повторного запуска теста:

  1. Новый массив байтов с использованием System.Array.Copy - 1.0781457 секунд
  2. Новый массив байтов с использованием System.Buffer.BlockCopy - 1.0156445 секунд
  3. IEnumerable & lt; byte> с использованием оператора C # yield - 0.0625012 секунд
  4. IEnumerable & lt; byte> с использованием Concact & lt;> - 0.07812 LINQ 65 секунд

Наконец, я увеличил размер каждого массива до 1 миллиона элементов и перезапустил тест, выполнив каждый цикл только 4000 раз:

  1. Новый байт-массив с использованием System.Array.Copy - 13.4533833 секунд
  2. Новый массив байтов с использованием System.Buffer.BlockCopy - 13.1096267 секунд
  3. IEnumerable & lt; byte> с использованием оператора C # yield - 0 секунд
  4. IEnumerable & lt; byte> используя Concact & lt;> - 0 секунд LINQ

Итак, если вам нужен новый массив байтов, используйте

byte[] rv = new byte[a1.Length + a2.Length + a3.Length];
System.Buffer.BlockCopy(a1, 0, rv, 0, a1.Length);
System.Buffer.BlockCopy(a2, 0, rv, a1.Length, a2.Length);
System.Buffer.BlockCopy(a3, 0, rv, a1.Length + a2.Length, a3.Length);

Но, если вы может использовать IEnumerable<byte>, DEFINITELY предпочитает метод Concat & lt;> LINQ. Это немного медленнее, чем оператор C # yield, но является более кратким и более элегантным.

IEnumerable<byte> rv = a1.Concat(a2).Concat(a3);

Если у вас есть произвольное количество массивов и вы используете .NET 3.5, вы можете сделать System.Buffer.BlockCopy Решение более общее:

private byte[] Combine(params byte[][] arrays)
{
    byte[] rv = new byte[arrays.Sum(a => a.Length)];
    int offset = 0;
    foreach (byte[] array in arrays) {
        System.Buffer.BlockCopy(array, 0, rv, offset, array.Length);
        offset += array.Length;
    }
    return rv;
}

* Примечание. В приведенном выше блоке вы должны добавить следующее пространство имен вверху, чтобы оно работало.

using System.Linq;

К Jon Skeet's (байтовый массив против IEnumerable & lt; byte>), я повторно запустил последний тест времени (1 миллион элементов, 4000 итераций), добавив цикл, который выполняет итерацию по всему массиву с каждым проходом:

  1. Массив нового байта с использованием System.Array.Copy - 78.20550510 секунд
  2. Новый байт-массив с использованием System.Buffer.BlockCopy - 77.89261900 секунд
  3. IEnumerable & lt; byte> с использованием C # yield оператор - 551.7150161 секунд
  4. IEnumerable & lt; byte> с использованием Concact & lt;> - 448.1804799 секунд LINQ

Суть в том, что ОЧЕНЬ важно, чтобы понять эффективность как креацио n и использование результирующей структуры данных. Простое сосредоточение на эффективности создания может не учитывать неэффективность, связанную с использованием. Кудос, Джон.

273
ответ дан Peter Mortensen 27 August 2018 в 15:23
поделиться

На самом деле я столкнулся с некоторыми проблемами с использованием Concat ... (с массивами в 10 миллионов, он фактически разбился).

Я нашел следующее, чтобы быть простым, легким и работать достаточно хорошо, без сбой на мне, и он работает для ЛЮБОГО числа массивов (не только трех) (он использует LINQ):

public static byte[] ConcatByteArrays(params byte[][]  arrays)
{
    return arrays.SelectMany(x => x).ToArray();
}
8
ответ дан 00jt 27 August 2018 в 15:23
поделиться

Класс memystream делает эту работу очень красиво для меня. Я не мог заставить класс буфера работать так же быстро, как memystream.

using (MemoryStream ms = new MemoryStream())
{
  ms.Write(BitConverter.GetBytes(22),0,4);
  ms.Write(BitConverter.GetBytes(44),0,4);
  ms.ToArray();
}
5
ответ дан Andrew 27 August 2018 в 15:23
поделиться

Все, что вам нужно, чтобы передать список байт-массивов, и эта функция вернет вам массив байтов (объединенный). Это лучшее решение, о котором я думаю:).

public static byte[] CombineMultipleByteArrays(List<byte[]> lstByteArray)
        {
            using (var ms = new MemoryStream())
            {
                using (var doc = new iTextSharp.text.Document())
                {
                    using (var copy = new PdfSmartCopy(doc, ms))
                    {
                        doc.Open();
                        foreach (var p in lstByteArray)
                        {
                            using (var reader = new PdfReader(p))
                            {
                                copy.AddDocument(reader);
                            }
                        }

                        doc.Close();
                    }
                }
                return ms.ToArray();
            }
        }
-1
ответ дан ARC 27 August 2018 в 15:23
поделиться

Может использовать generics для объединения массивов. Следующий код можно легко расширить до трех массивов. Таким образом, вам не нужно дублировать код для разных типов массивов. Некоторые из приведенных выше ответов кажутся мне слишком сложными.

private static T[] CombineTwoArrays<T>(T[] a1, T[] a2)
    {
        T[] arrayCombined = new T[a1.Length + a2.Length];
        Array.Copy(a1, 0, arrayCombined, 0, a1.Length);
        Array.Copy(a2, 0, arrayCombined, a1.Length, a2.Length);
        return arrayCombined;
    }
0
ответ дан BajaPaul 27 August 2018 в 15:23
поделиться
    public static bool MyConcat<T>(ref T[] base_arr, ref T[] add_arr)
    {
        try
        {
            int base_size = base_arr.Length;
            int size_T = System.Runtime.InteropServices.Marshal.SizeOf(base_arr[0]);
            Array.Resize(ref base_arr, base_size + add_arr.Length);
            Buffer.BlockCopy(add_arr, 0, base_arr, base_size * size_T, add_arr.Length * size_T);
        }
        catch (IndexOutOfRangeException ioor)
        {
            MessageBox.Show(ioor.Message);
            return false;
        }
        return true;
    }
2
ответ дан edd 27 August 2018 в 15:23
поделиться

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

byte[] Combine(byte[] a1, byte[] a2, byte[] a3)
{
    byte[] ret = new byte[a1.Length + a2.Length + a3.Length];
    Array.Copy(a1, 0, ret, 0, a1.Length);
    Array.Copy(a2, 0, ret, a1.Length, a2.Length);
    Array.Copy(a3, 0, ret, a1.Length + a2.Length, a3.Length);
    return ret;
}

В качестве альтернативы, если вам нужен только один IEnumerable, подумайте о том, как использовать оператор yield C # 2.0:

IEnumerable<byte> Combine(byte[] a1, byte[] a2, byte[] a3)
{
    foreach (byte b in a1)
        yield return b;
    foreach (byte b in a2)
        yield return b;
    foreach (byte b in a3)
        yield return b;
}
26
ответ дан FryGuy 27 August 2018 в 15:23
поделиться

Многие из ответов, как мне кажется, игнорируют указанные требования:

  • Результатом должен быть массив байтов
  • Он должен быть как можно более эффективным

Эти два вместе исключают последовательность байтов LINQ - что-либо с yield будет делать невозможным получение окончательного размера без итерации по всей последовательности.

Если это не требования real , конечно, LINQ может быть идеальным решением (или реализацией IList<T>). Тем не менее, я предполагаю, что Superdumbell знает, чего он хочет.

(EDIT: У меня была другая мысль: существует большая смысловая разница между копированием массивов и ленивым чтением. происходит, если вы измените данные в одном из массивов «источник» после вызова метода Combine (или любого другого), но перед использованием результата - с ленивой оценкой это изменение будет видимым. С немедленной копией он не будет Различные ситуации потребуют различного поведения - просто что-то, о чем нужно знать.)

Вот мои предложенные методы, которые очень похожи на те, что содержатся в некоторых других ответах, конечно:)

public static byte[] Combine(byte[] first, byte[] second)
{
    byte[] ret = new byte[first.Length + second.Length];
    Buffer.BlockCopy(first, 0, ret, 0, first.Length);
    Buffer.BlockCopy(second, 0, ret, first.Length, second.Length);
    return ret;
}

public static byte[] Combine(byte[] first, byte[] second, byte[] third)
{
    byte[] ret = new byte[first.Length + second.Length + third.Length];
    Buffer.BlockCopy(first, 0, ret, 0, first.Length);
    Buffer.BlockCopy(second, 0, ret, first.Length, second.Length);
    Buffer.BlockCopy(third, 0, ret, first.Length + second.Length,
                     third.Length);
    return ret;
}

public static byte[] Combine(params byte[][] arrays)
{
    byte[] ret = new byte[arrays.Sum(x => x.Length)];
    int offset = 0;
    foreach (byte[] data in arrays)
    {
        Buffer.BlockCopy(data, 0, ret, offset, data.Length);
        offset += data.Length;
    }
    return ret;
}

Конечно, версия «params» требует создания массива массивов байтов, что приводит к дополнительной неэффективности.

124
ответ дан Jon Skeet 27 August 2018 в 15:23
поделиться

Конкат - это правильный ответ, но по какой-то причине наибольшее количество голосов получает зарубленная вещь. Если вам нравится этот ответ, возможно, вам понадобится еще более общее решение:

    IEnumerable<byte> Combine(params byte[][] arrays)
    {
        foreach (byte[] a in arrays)
            foreach (byte b in a)
                yield return b;
    }

, который позволит вам делать такие вещи, как:

    byte[] c = Combine(new byte[] { 0, 1, 2 }, new byte[] { 3, 4, 5 }).ToArray();
-5
ответ дан Mark Maxham 27 August 2018 в 15:23
поделиться

Я сделал пример Мэтта LINQ еще одним шагом для обеспечения чистоты кода:

byte[] rv = a1.Concat(a2).Concat(a3).ToArray();

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

26
ответ дан Nate Barbettini 27 August 2018 в 15:23
поделиться

Вот обобщение ответа, предоставленного @Jon Skeet. Это в основном то же самое, только он может использоваться для любого типа массива, а не только для байтов:

public static T[] Combine<T>(T[] first, T[] second)
{
    T[] ret = new T[first.Length + second.Length];
    Buffer.BlockCopy(first, 0, ret, 0, first.Length);
    Buffer.BlockCopy(second, 0, ret, first.Length, second.Length);
    return ret;
}

public static T[] Combine<T>(T[] first, T[] second, T[] third)
{
    T[] ret = new T[first.Length + second.Length + third.Length];
    Buffer.BlockCopy(first, 0, ret, 0, first.Length);
    Buffer.BlockCopy(second, 0, ret, first.Length, second.Length);
    Buffer.BlockCopy(third, 0, ret, first.Length + second.Length,
                     third.Length);
    return ret;
}

public static T[] Combine<T>(params T[][] arrays)
{
    T[] ret = new T[arrays.Sum(x => x.Length)];
    int offset = 0;
    foreach (T[] data in arrays)
    {
        Buffer.BlockCopy(data, 0, ret, offset, data.Length);
        offset += data.Length;
    }
    return ret;
}
1
ответ дан o_c 27 August 2018 в 15:23
поделиться
    public static byte[] Concat(params byte[][] arrays) {
        using (var mem = new MemoryStream(arrays.Sum(a => a.Length))) {
            foreach (var array in arrays) {
                mem.Write(array, 0, array.Length);
            }
            return mem.ToArray();
        }
    }
2
ответ дан Peter Ertl 27 August 2018 в 15:23
поделиться
Другие вопросы по тегам:

Похожие вопросы: