概述C#語言的結構體
最近一直在研究。Net Micro Framework字體文件(tinyfnt),由于tinyfnt文件頭部有一段描述數(shù)據(jù),所以很想定義一個結構體,像VC一樣直接從文件中讀出來,省得用流一個個解析很是麻煩。
沒有想到在C#中竟沒有直接的指令,想必C#設計者認為提供了流和序列化技術,一切問題都可以迎刃而解了。
C#語言的結構體是一個比較復雜的東西,在此之上有很多需要設置的參數(shù),否則用起來就很容易出錯。下面是msdn上一段描述,看看也許有助于理解C#語言的結構體。
通過使用屬性可以自定義結構在內(nèi)存中的布局方式。例如,可以使用 StructLayout(LayoutKind.Explicit) 和 FieldOffset 屬性創(chuàng)建在 C/C++ 中稱為聯(lián)合的布局。
- [System.Runtime.InteropServices.StructLayout(LayoutKind.Explicit)]
- struct TestUnion
- {
- [System.Runtime.InteropServices.FieldOffset(0)]
- public int i;
- [System.Runtime.InteropServices.FieldOffset(0)]
- public double d;
- [System.Runtime.InteropServices.FieldOffset(0)]
- public char c;
- [System.Runtime.InteropServices.FieldOffset(0)]
- public byte b;
- }
在上一個代碼段中,TestUnion 的所有字段都從內(nèi)存中的同一位置開始。
以下是字段從其他顯式設置的位置開始的另一個示例。
- [System.Runtime.InteropServices.StructLayout(LayoutKind.Explicit)]
- struct TestExplicit
- {
- [System.Runtime.InteropServices.FieldOffset(0)]
- public long lg;
- [System.Runtime.InteropServices.FieldOffset(0)]
- public int i1;
- [System.Runtime.InteropServices.FieldOffset(4)]
- public int i2;
- [System.Runtime.InteropServices.FieldOffset(8)]
- public double d;
- [System.Runtime.InteropServices.FieldOffset(12)]
- public char c;
- [System.Runtime.InteropServices.FieldOffset(14)]
- public byte b;
- }
i1 和 i2 這兩個 int 字段共享與 lg 相同的內(nèi)存位置。使用平臺調(diào)用時,這種結構布局控制很有用。
我做了一個簡單的測試程序,基本達成預定需求,不過程序該方式要求比較苛刻,如果要解析的數(shù)據(jù)與轉(zhuǎn)換C#語言的結構體不匹配就會引發(fā)一系列莫名其妙的異常(如內(nèi)存不可讀等等之類),下面是測試程序的源代碼,有興趣的朋友可以看一看,也希望網(wǎng)友能提出更好的方案。
- using System;
- using System.Collections.Generic;
- using System.ComponentModel;
- using System.Data;
- using System.Drawing;
- using System.Text;
- using System.Windows.Forms;
- using System.IO;
- using System.Runtime.InteropServices;
- namespace RWFile
- {
- public partial class Form1 : Form
- {
- public Form1()
- {
- InitializeComponent();
- }
- //從文件中讀結構體
- private void button1_Click(object sender, EventArgs e)
- {
- string strFile = Application.StartupPath + "\\test.dat";
- if (!File.Exists(strFile))
- {
- MessageBox.Show("文件不存在");
- return;
- }
- FileStream fs = new FileStream(strFile, FileMode.Open,
- FileAccess.ReadWrite);
- TestStruct ts = new TestStruct();
- byte[] bytData = new byte[Marshal.SizeOf(ts)];
- fs.Read(bytData, 0, bytData.Length);
- fs.Close();
- ts = rawDeserialize(bytData);
- textBox1.Text = ts.dTest.ToString();
- textBox2.Text = ts.uTest.ToString();
- textBox3.Text = Encoding.Default.GetString(ts.bTest);
- }
- //向文件中寫結構體
- private void button2_Click(object sender, EventArgs e)
- {
- string strFile = Application.StartupPath + "\\test.dat";
- FileStream fs = new FileStream(strFile, FileMode.Create ,
- FileAccess.Write);
- TestStruct ts = new TestStruct();
- ts.dTest = double.Parse(textBox1.Text);
- ts.uTest = UInt16.Parse(textBox2.Text);
- ts.bTest = Encoding.Default.GetBytes(textBox3.Text);
- byte[] bytData = rawSerialize(ts);
- fs.Write(bytData, 0, bytData.Length);
- fs.Close();
- }
- [StructLayout(LayoutKind.Sequential,CharSetCharSet = CharSet.Ansi)] //,Size=16
- public struct TestStruct
- {
- [MarshalAs(UnmanagedType.R8)] //,FieldOffset(0)]
- public double dTest;
- [MarshalAs(UnmanagedType.U2)] //, FieldOffset(8)]
- public UInt16 uTest;
- [MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)]
- //, FieldOffset(10)]
- public byte[] bTest;
- }
- //序列化
- public static byte[] rawSerialize(object obj)
- {
- int rawsize = Marshal.SizeOf(obj);
- IntPtr buffer = Marshal.AllocHGlobal(rawsize);
- Marshal.StructureToPtr(obj, buffer, false);
- byte[] rawdatas = new byte[rawsize];
- Marshal.Copy(buffer, rawdatas, 0, rawsize);
- Marshal.FreeHGlobal(buffer);
- return rawdatas;
- }
- //反序列化
- public static TestStruct rawDeserialize(byte[] rawdatas)
- {
- Type anytype = typeof(TestStruct);
- int rawsize = Marshal.SizeOf(anytype);
- if (rawsize > rawdatas.Length) return new TestStruct();
- IntPtr buffer = Marshal.AllocHGlobal(rawsize);
- Marshal.Copy(rawdatas, 0, buffer, rawsize);
- object retobj = Marshal.PtrToStructure(buffer, anytype);
- Marshal.FreeHGlobal(buffer);
- return (TestStruct)retobj;
- }
- }
- }
【編輯推薦】