结构体:探析C#文件方式读写结构体

最近直在研究Net Micro Framework字体文件(tinyfnt)由于tinyfnt文件头部有段描述数据所以很想

定义个结构体像VC样直接从文件中读出来省得用流个个解析很是麻烦   没有想到在中竟没有直接指令想必设

计者认为提供了流和序列化技术切问题都可以迎刃而解了

  在中结构体是个比较复杂东西在此的上有很多需要设置参数否则用起来就很容易出错下面是msdn上段描述

看看也许有助于理解C#语言中结构体

  通过使用属性可以自定义结构在内存中布局方式例如可以使用 StructLayout(LayoutKind.Explicit) 和

FieldOff 属性创建在 C/C 中称为联合布局

[.Runtime.InteropServices.StructLayout(LayoutKind.Explicit)]

struct TestUnion

{

[.Runtime.InteropServices.FieldOff(0)]

public i;

[.Runtime.InteropServices.FieldOff(0)]

public double d;

[.Runtime.InteropServices.FieldOff(0)]

public char c;

[.Runtime.InteropServices.FieldOff(0)]

public b;

}  在上个代码段中TestUnion 所有字段都从内存中同位置开始

  以下是字段从其他显式设置位置开始另个举例

[.Runtime.InteropServices.StructLayout(LayoutKind.Explicit)]

struct TestExplicit

{

[.Runtime.InteropServices.FieldOff(0)]

public long lg;

[.Runtime.InteropServices.FieldOff(0)]

public i1;

[.Runtime.InteropServices.FieldOff(4)]

public i2;

[.Runtime.InteropServices.FieldOff(8)] 

public double d;

[.Runtime.InteropServices.FieldOff(12)]

public char c;

[.Runtime.InteropServices.FieldOff(14)]

public b;

}  i1 和 i2 这两个 字段共享和 lg 相同内存位置使用平台时这种结构布局控制很有用

  我做了个简单测试基本达成预定需求不过该方式要求比较苛刻如果要解析数据和转换结构体不匹配就会

引发系列莫名其妙异常(如内存不可读等等的类)下面是测试源代码有兴趣朋友可以看看也希望网友能提出更好方



using ;

using .Collections.Generic;

using .ComponentModel;

using .Data;

using .Drawing;

using .Text;

using ..Forms;

using .IO;

using .Runtime.InteropServices;

RWFile

{

public partial Form1 : Form

{

public Form1

{

InitializeComponent;

}

//从文件中读结构体

private void button1_Click(object sender, EventArgs e)

{

strFile = Application.StartupPath + "  est.dat";

(!File.Exists(strFile))

{

MessageBox.Show("文件不存在");



}

FileStream fs = FileStream(strFile, FileMode.Open,

FileAccess.ReadWrite);

TestStruct ts = TestStruct;

bytData = [Marshal.SizeOf(ts)];

fs.Read(bytData, 0, bytData.Length);

fs.Close;

ts = rawDeserialize(bytData);

textBox1.Text = ts.dTest.;

textBox2.Text = ts.uTest.;

textBox3.Text = Encoding.Default.GetString(ts.bTest);

}

//向文件中写结构体

private void button2_Click(object sender, EventArgs e)

{

strFile = Application.StartupPath + "  est.dat";

FileStream fs = FileStream(strFile, FileMode.Create ,

                      FileAccess.Write);

TestStruct ts = TestStruct;

ts.dTest = double.Parse(textBox1.Text);

ts.uTest = UInt16.Parse(textBox2.Text);

ts.bTest = Encoding.Default.GetBytes(textBox3.Text);

bytData = rawSerialize(ts);

fs.Write(bytData, 0, bytData.Length);

fs.Close;

}

[StructLayout(LayoutKind.Sequential,CharSet = CharSet.Ansi)] //,Size=16

public struct TestStruct

{

[MarshalAs(UnmanagedType.R8)] //,FieldOff(0)] 

public double dTest;

[MarshalAs(UnmanagedType.U2)] //, FieldOff(8)]

public UInt16 uTest;

[MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)]

                 //, FieldOff(10)]

public bTest; 

}

//序列化

public rawSerialize(object obj)

{

rawsize = Marshal.SizeOf(obj);

IntPtr buffer = Marshal.AllocHGlobal(rawsize);

Marshal.StructureToPtr(obj, buffer, false);

rawdatas = [rawsize];

Marshal.Copy(buffer, rawdatas, 0, rawsize);

Marshal.FreeHGlobal(buffer);

rawdatas;

}

//反序列化

public TestStruct rawDeserialize( rawdatas)

{

Type anytype = typeof(TestStruct);

rawsize = Marshal.SizeOf(anytype);

(rawsize > rawdatas.Length) TestStruct;

IntPtr buffer = Marshal.AllocHGlobal(rawsize);

Marshal.Copy(rawdatas, 0, buffer, rawsize);

object retobj = Marshal.PtrToStructure(buffer, anytype);

Marshal.FreeHGlobal(buffer);

(TestStruct)retobj;

}   

}

}

上一篇:C语言博客作业06——结构体&文件


下一篇:ARM单片机的头文件如何用结构体定义地址