在C#中将字节读入结构

时间:2010-07-14 18:14:23

标签: c# file-io struct

另一个离墙问题的时间。我正在为我的小型3D引擎项目编写MD2加载程序。在我的旧语言(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));

我意识到这是不正确的,因为它有点奇怪地打破了类型安全,但是你知道我想要完成什么。我可以通过单独调用reader.ReadInt32()来做到这一点,但我很好奇是否有任何方式让我按照我希望使用普通库调用的方式工作。

我看了一下Marshal.Copy()方法,但它似乎是在托管和非托管内存之间进行的,这不是我在这里做的。

有什么建议吗?

7 个答案:

答案 0 :(得分:5)

将字节流读取到字节数组,将其命名为packet,然后尝试以下操作:

GCHandle pinned = GCHandle.Alloc(packet, GCHandleType.Pinned);
MD2_Header h = (MD2_Header)Marshal.PtrToStructure(pinned.AddrOfPinnedObject(), typeof(MD2_Header));
pinned.Free();

答案 1 :(得分:3)

您可以使用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)
          );
}

答案 2 :(得分:3)

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 :(得分:1)

你可以做的是将字节读入适当大小的缓冲区,使用fixed (int* = &md2hdr.FourCC)获取指向结构开头的指针,将指向结构的指针强制转换为byte*,手动复制字节。

答案 4 :(得分:1)

您可以使用编组来处理复制。无需编写代码来处理它。

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

答案 5 :(得分:1)

我知道你已经有了答案,这是一个很好的答案。

我认为你可以从我在.NET中提供的一些选项上做的博客文章中获得一些价值。

Structure from binary data

反向的相应帖子

Binary data from a structure

答案 6 :(得分:0)

在C#中可能会有点复杂,但是可以设置可以将字节数组中的字节存储到结构中的位置。