关于结构与结构序列化的非常专业的文章: 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();