Как маршалировать массив байтов в структуру?

Связанный вопрос

В связанном с этим вопросе я пытался выяснить самый быстрый способ. Метод, который я выбрал в этом вопросе, стал для меня узким местом. Я читаю некоторые двоичные данные из файла, и мне нужно поместить их в определение управляемой структуры. Неуправляемый код не задействован, поэтому я думаю, что есть лучший способ, чем выделение GCHandle.

Есть ли способ просто преобразовать массив байтов в структуру того же размера?


person scottm    schedule 21.07.2009    source источник


Ответы (2)


У меня есть такой метод:

static public T ReadStructure<T>(byte[] bytes)
    where T : struct
{
    int len = Marshal.SizeOf(typeof(T));
    IntPtr i = Marshal.AllocHGlobal(len);

    try
    {
        Marshal.Copy(bytes, 0, i, len);
        return (T)Marshal.PtrToStructure(i, typeof(T));
    }
    finally
    {
        Marshal.FreeHGlobal(i);
    }
}

По общему признанию, это не очень быстро, но в моем случае это и не нужно. Это ваше текущее решение, и вы обнаружите, что накладные расходы на выделение/копирование/выпуск слишком медленные?

person Ben M    schedule 21.07.2009
comment
Я могу попробовать это. Проблема в том, что мне нужно прочитать 254 байта, проверить, содержат ли первые 240 тип, и если да, то двигаться дальше. С помощью этого метода я читаю данные из файла, копирую первые 240 байт в указатель, проверяю его, затем копирую все 254 байта в указатель. Происходит много копирования. - person scottm; 21.07.2009
comment
Похоже, есть несколько способов оптимизации. Не могли бы вы опубликовать код? - person Ben M; 21.07.2009
comment
@ Бен, в соответствующем вопросе есть пример того, что я сейчас делаю. - person scottm; 21.07.2009
comment
Поскольку вы читаете из файла, вы можете подумать о P/вызове методов доступа к файлам Win32; вы можете выделить большой кусок памяти как IntPtr, прочитать его напрямую, а затем маршалировать прямо из него, не копируя в/из управляемого буфера byte[]. - person Ben M; 21.07.2009
comment
Я попробовал это. Это кажется немного быстрее и определенно использует меньше памяти. посмотрю как пойдет, спасибо - person scottm; 21.07.2009

Вы можете проверить такой код:


struct Foo
{
  public int x;
}

public unsafe static void Main()
{
  byte[] x = new byte[] { 1, 1, 0, 0 };
  Foo f;

  fixed (byte* xPtr = x)
  {
    f = *((Fpp*)xPtr);
  }

  Console.WriteLine(f.x);
}

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

person Marcin Deptuła    schedule 21.07.2009
comment
Каковы последствия использования этого метода в 32/64-битных границах? Есть ли способ гарантировать одинаковые представления на всех машинах, которые могут совместно использовать данные, хранящиеся и считываемые с помощью этого метода? - person Ben M; 21.07.2009
comment
Что такое Фпп? Когда я пытаюсь выполнить аналогичное объявление, используя свой тип, я получаю сообщение Невозможно взять адрес, получить размер или объявить указатель на управляемый тип. - person scottm; 21.07.2009
comment
Я думаю, что он хотел написать Foo, а не Fpp. - person Ben M; 21.07.2009
comment
Да, это должно быть Foo, а не Fpp :). Что касается 32/64-битных границ - 1. У вас будут некоторые проблемы с указателями, 2. По умолчанию структуры в c# имеют последовательную компоновку, так что больших сюрпризов с ними не должно быть. 3. Вы можете использовать [StructLayout(Explicit)] и расположить его по своему усмотрению. Кстати, этот метод не тот метод, который я бы использовал для производственного кода, есть места, где он может сломаться. - person Marcin Deptuła; 21.07.2009