Чтение байтов в структуру в C#

время для другого от вопроса о стене. Я пишу загрузчик MD2 для своего маленького 3D проекта механизма. На моем старом языке (C) я мог определить структуру и затем читать () из открытого файла непосредственно в структуру. У меня есть структура для содержания информации заголовка из файла MD2, следующим образом:

[StructLayout(LayoutKind.Sequential)]
public struct MD2_Header
{
    public int FourCC;
    public int Version;
    public int TextureWidth;
    public int TextureHeight;
    public int FrameSizeInBytes;
    public int NbrTextures;
    public int NbrVertices;
    public int NbrTextureCoords;
    public int NbrTriangles;
    public int NbrOpenGLCmds;
    public int NbrFrames;
    public int TextureOffset;
    public int TexCoordOffset;
    public int TriangleOffset;
    public int FrameOffset;
    public int OpenGLCmdOffset;
    public int EndOffset;
}

В моем коде читателя я хотел бы сделать что-то как:

// Suck the MD2 header into a structure, it is 68 bytes long.
Classic.Util.MD2_Header md2hdr = new Classic.Util.MD2_Header();
md2hdr = reader.ReadBytes(sizeof(Classic.Util.MD2_Header));

Я понимаю, что это не корректно, поскольку это повреждает безопасность типов несколько странно, но Вы получаете идею того, что я хочу выполнить. Я мог сделать это с отдельными вызовами читателю. ReadInt32 (), но мне любопытно, если там должен так или иначе заставить это прокладывать себе путь, я желаю использовать нормальные вызовы библиотеки.

Я немного изучил Маршала. Копия () метод, но это, кажется, для движения между управляемой и неуправляемой памятью, которая не является действительно, что я делаю здесь.

Какие-либо предложения?

6
задан Chris D. 14 July 2010 в 18:14
поделиться

7 ответов

Структура в C и структура в C# - это две совершенно разные вещи. Структура в C используется как для типов значений, так и для ссылочных типов, а структура в C# используется только для типов значений.

Тип значения должен представлять одно значение, но у вас много значений, поэтому вместо него следует использовать класс. Рекомендуемый максимальный размер структуры в .NET - 16 байт, а у вас в четыре раза больше данных.

Класс со свойствами и конструктором, принимающим байтовый массив, будет выглядеть так:

public class MD2_Header {

  public int FourCC { get; set; }
  public int Version { get; set; };
  public int TextureWidth { get; set; };
  public int TextureHeight { get; set; };
  public int FrameSizeInBytes { get; set; };
  public int NbrTextures { get; set; };
  public int NbrVertices { get; set; };
  public int NbrTextureCoords { get; set; };
  public int NbrTriangles { get; set; };
  public int NbrOpenGLCmds { get; set; };
  public int NbrFrames { get; set; };
  public int TextureOffset { get; set; };
  public int TexCoordOffset { get; set; };
  public int TriangleOffset { get; set; };
  public int FrameOffset { get; set; };
  public int OpenGLCmdOffset { get; set; };
  public int EndOffset { get; set; };

  public MD2_Header(byte[] values) {
    FourCC = BitConverter.ToInt32(values, 0);
    Version = BitConverter.ToInt32(values, 4);
    TextureWidth = BitConverter.ToInt32(values, 8);
    TextureHeight = BitConverter.ToInt32(values, 12);
    FrameSizeInBytes = BitConverter.ToInt32(values, 16);
    NbrTextures = BitConverter.ToInt32(values, 20);
    NbrVertices = BitConverter.ToInt32(values, 24);
    NbrTextureCoords = BitConverter.ToInt32(values, 28);
    NbrTriangels = BitConverter.ToInt32(values, 32);
    NbrOpenGLCmds = BitConverter.ToInt32(values, 36);
    NbrFrames = BitConverter.ToInt32(values, 40);
    TextureOffset = BitConverter.ToInt32(values, 44);
    TexCoordOffset = BitConverter.ToInt32(values, 48);
    TriangleOffset = BitConverter.ToInt32(values, 52);
    FrameOffset = BitConverter.ToInt32(values, 56);
    OpenGLCmdOffset = BitConverter.ToInt32(values, 60);
    EndOffset = BitConverter.ToInt32(values, 64);
  }

}
3
ответ дан 8 December 2019 в 17:18
поделиться

Я знаю, что у вас уже есть ответ, и это хороший ответ.

Я подумал, что вы можете получить некоторую ценность от сообщения в блоге, которое я сделал по некоторым опциям, доступным в .NET, чтобы достичь этого.

Структура из двоичных данных

И соответствующий пост для обратного

Двоичные данные из структуры

1
ответ дан 8 December 2019 в 17:18
поделиться

Для обработки копирования можно использовать маршалинг. Нет необходимости писать код для его обработки.

//create object
Classic.Util.MD2_Header md2hdr = new Classic.Util.MD2_Header();
Classic.Util.MD2_Header another = new Classic.Util.MD2_Header();
byte[] mem = new byte[Marshal.SizeOf(typeof(MD2_Header))];

//allocate unmanaged memory
IntPtr hmem = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(Classic.Util.MD2_Header)));

//copy structure to unmanaged memory
Marshal.StructureToPtr(md2hdr, hmem, false);

//copy to managed memory
Marshal.Copy(hmem, mem, 0, mem.Length);

//copy unmanaged memory to structure
another = (Classic.Util.MD2_Header)Marshal.PtrToStructure(hmem, typeof(Classic.Util.MD2_Header));

//free unmanaged memory
Marshal.FreeHGlobal(hmem);
1
ответ дан 8 December 2019 в 17:18
поделиться

Это может быть немного сложным в C #, но вы можете настроить вещи, в которых вы можете скопировать байты из байтового массива в структуру.

0
ответ дан 8 December 2019 в 17:18
поделиться

Прочтите поток байтов в массив байтов, назовите его пакет и попробуйте следующее:

GCHandle pinned = GCHandle.Alloc(packet, GCHandleType.Pinned);
MD2_Header h = (MD2_Header)Marshal.PtrToStructure(pinned.AddrOfPinnedObject(), typeof(MD2_Header));
pinned.Free();
5
ответ дан 8 December 2019 в 17:18
поделиться

Что вы можете сделать, так это прочитать байты в буфер подходящего размера, используйте fixed (int * = & md2hdr.FourCC) , чтобы получить указатель на в начале вашей структуры, переведите указатель на вашу структуру на байт * и скопируйте байты вручную.

1
ответ дан 8 December 2019 в 17:18
поделиться

Вы можете использовать Marshal.PtrToStructure для копирования из указателя прямо в вашу структуру одним выстрелом. Автор

byte[] data = reader.ReadBytes(...);
fixed (byte* bytes = data)
{
     Classic.Util.MD2_Header md2hdr = 
          (Classic.Util.MD2_Header)Marshal.PtrToStructure(
               Marshal.UnsafeAddrOfPinnedArrayElement(data, 0),
               typeof(Classic.Util.MD2_Header)
          );
}
3
ответ дан 8 December 2019 в 17:18
поделиться
Другие вопросы по тегам:

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