C# struct 的种种

关于结构与结构序列化的非常专业的文章:  Quick Serialization/Deserialization of a Managed Structure.  文章写得太教科书了,就读这一篇足矣。

 当你要把含有 string 的 struct 用序列化保存到文件时, 要用 MarshalAs 显式地把 string 模仿非托管类型。

[StructLayout(LayoutKind.Explicit)]
struct StructType
{
    [FieldOffset(0)]
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 8)]
    public string FileDate;

    [FieldOffset(8)]
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 8)]
    public string FileTime;

    [FieldOffset(16)]
    public int Id1;

    [FieldOffset(20)]
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 66)] //Or however long Id2 is.
    public string Id2;
}

另一个结构的例子

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode, Pack = 1)]
struct MyDataStruct
{
  [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
  public string strMember;
  public Int32 int32Member;
  public byte byteMember;
  public double dblMember;
  [MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.I1, SizeConst = 10)]
  public char[] chArrayMember;
}

一个序列化完整的说明例子, 在 struct 中定义方法  

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode, Pack = 1)]
struct MyDataStruct
{
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
    public string strMember;
    public Int32 int32Member;
    public byte byteMember;
    public double dblMember;
    [MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.I1, SizeConst = 10)]
    public char[] chArrayMember;

    // Member function for serialization.
    public byte[] Serialize()
        {
          ...
        }

    // Member function for deserialization.
    public void Deserialize(ref byte[] byteSerializedData)
        {
          ...
        }
}

其中 Serialize 方法

public byte[] Serialize()
{
    // Get the byte size of a MyDataStruct structure if it is to be
    // marshaled to unmanaged memory.
    Int32 iSizeOMyDataStruct = Marshal.SizeOf(typeof(MyDataStruct));
    // Allocate a byte array to contain the bytes of the unmanaged version
    // of the MyDataStruct structure.
    byte[] byteArrayMyDataStruct = new byte[iSizeOMyDataStruct];
    // Allocate a GCHandle to pin the byteArrayMyDataStruct array
    // in memory in order to obtain its pointer.
    GCHandle gch = GCHandle.Alloc(byteArrayMyDataStruct, GCHandleType.Pinned);
    // Obtain a pointer to the byteArrayMyDataStruct array in memory.
    IntPtr pbyteArrayMyDataStruct = gch.AddrOfPinnedObject();
    // Copy all bytes from the managed MyDataStruct structure into
    // the byte array.
    Marshal.StructureToPtr(this, pbyteArrayMyDataStruct, false);
    // Unpin the byteArrayMyDataStruct array in memory.
    gch.Free();
    // Return the byte array.
    // It contains the serialized bytes of the MyDataStruct structure.
    return byteArrayMyDataStruct;
}

其中的 Deserialize 方法

public void Deserialize(ref byte[] byteSerializedData)
{
    // Allocate a GCHandle of the Pinned Type
    // for the byteSerializedData byte array.
    // This is possible for a byte array
    // because it is a blittable type.
    GCHandle gch = GCHandle.Alloc(byteSerializedData, GCHandleType.Pinned);
    // Get a pointer to the byteSerializedData array.
    IntPtr pbyteSerializedData = gch.AddrOfPinnedObject();
    // Convert the array data of byteSerializedData
    // directly into a MyDataStruct structure.
    // The interop marshaler will use the MarshalAsAttribute
    // of the fields of the MyDataStruct structure to
    // perform field data conversions.
    this = (MyDataStruct)Marshal.PtrToStructure(pbyteSerializedData, typeof(MyDataStruct));
    // Free the GCHandle.
    gch.Free();
}
Serialize 方法测试
public static void TestSerializeMyDataStruct()
{
    // Allocate a new MyDataStruct structure.
    MyDataStruct my_data_struct = new MyDataStruct();

    // Assign values to the fields of the structure.
    my_data_struct.strMember = "Hello World";
    my_data_struct.int32Member = 100;
    my_data_struct.byteMember = (byte)'A';
    my_data_struct.dblMember = 0.123456;
    my_data_struct.chArrayMember = new char[10];
    for (int i = 0; i < my_data_struct.chArrayMember.Length; i++)
    {
        my_data_struct.chArrayMember[i] = (char)('A' + (char)i);
    }

    // Serialize the MyDataStruct structure into an array
    // of bytes.
    byte[] byArraySerializedData = my_data_struct.Serialize();

    // Save the array contents into an external file.
    FileStream file_stream = File.OpenWrite("MyDataStruct.bin");
    // Write the full contents of byArraySerializedData into the file stream.
    file_stream.Write(byArraySerializedData, 0, byArraySerializedData.Length);
    // Close the file stream when done.
    file_stream.Close();
}

 Deserialize 方法测试

public static void TestDeserializeMyDataStructure()
{
    FileStream file_stream = File.OpenRead("MyDataStruct.bin");

    // Allocate a byte array the size of the length of the file.
    byte[] byArraySerializedData = new byte[file_stream.Length];
    // Read the full contents of file into the file stream.
    file_stream.Read(byArraySerializedData, 0, byArraySerializedData.Length);
    // Close the file stream when done.
    file_stream.Close();

    // Deserialize the contents of byArraySerializedData into
    // a MyDataStruct structure.
    MyDataStruct my_data_struct = new MyDataStruct();
    my_data_struct.Deserialize(ref byArraySerializedData);
}

 此文和前文写得一样好 C# Read and Write Between Struct and Stream | Computing ...


 

查看相关资料看到其它的相关内容, 对理解有用, 也存在此。 

c# - Read binary file into a struct - Stack Overflow

 

 用反序列化读入

using (FileStream stream = new FileStream(fileName, FileMode.Open))
{
    BinaryFormatter formatter = new BinaryFormatter();
    StructType aStruct = (StructType)formatter.Deserialize(filestream);
}

另一段代码

StructType aStruct;
int count = Marshal.SizeOf(typeof(StructType));
byte[] readBuffer = new byte[count];
BinaryReader reader = new BinaryReader(stream);
readBuffer = reader.ReadBytes(count);
GCHandle handle = GCHandle.Alloc(readBuffer, GCHandleType.Pinned);
aStruct = (StructType) Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(StructType));
handle.Free();

 

posted @ 2016-12-11 08:01  ouyang80  阅读(336)  评论(0编辑  收藏  举报