概述C#語言的結(jié)構(gòu)體
最近一直在研究。Net Micro Framework字體文件(tinyfnt),由于tinyfnt文件頭部有一段描述數(shù)據(jù),所以很想定義一個(gè)結(jié)構(gòu)體,像VC一樣直接從文件中讀出來,省得用流一個(gè)個(gè)解析很是麻煩。
沒有想到在C#中竟沒有直接的指令,想必C#設(shè)計(jì)者認(rèn)為提供了流和序列化技術(shù),一切問題都可以迎刃而解了。
C#語言的結(jié)構(gòu)體是一個(gè)比較復(fù)雜的東西,在此之上有很多需要設(shè)置的參數(shù),否則用起來就很容易出錯(cuò)。下面是msdn上一段描述,看看也許有助于理解C#語言的結(jié)構(gòu)體。
通過使用屬性可以自定義結(jié)構(gòu)在內(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;
 - }
 
在上一個(gè)代碼段中,TestUnion 的所有字段都從內(nèi)存中的同一位置開始。
以下是字段從其他顯式設(shè)置的位置開始的另一個(gè)示例。
- [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 這兩個(gè) int 字段共享與 lg 相同的內(nèi)存位置。使用平臺(tái)調(diào)用時(shí),這種結(jié)構(gòu)布局控制很有用。
我做了一個(gè)簡單的測(cè)試程序,基本達(dá)成預(yù)定需求,不過程序該方式要求比較苛刻,如果要解析的數(shù)據(jù)與轉(zhuǎn)換C#語言的結(jié)構(gòu)體不匹配就會(huì)引發(fā)一系列莫名其妙的異常(如內(nèi)存不可讀等等之類),下面是測(cè)試程序的源代碼,有興趣的朋友可以看一看,也希望網(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();
 - }
 - //從文件中讀結(jié)構(gòu)體
 - 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);
 - }
 - //向文件中寫結(jié)構(gòu)體
 - 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;
 - }
 - }
 - }
 
【編輯推薦】















 
 
 

 
 
 
 