c#

位置:IT落伍者 >> c# >> 浏览文章

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


发布日期:2020年03月23日
 
探析C#文件方式读写结构体

最近一直在研究Net Micro Framework字体文件(tinyfnt)由于tinyfnt文件头部有一段描述数据所以很想定义一个结构体像VC一样直接从文件中读出来省得用流一个个解析很是麻烦

没有想到在C#中竟没有直接的指令想必C#设计者认为提供了流和序列化技术一切问题都可以迎刃而解了

在C#中结构体是一个比较复杂的东西在此之上有很多需要设置的参数否则用起来就很容易出错下面是msdn上一段描述看看也许有助于理解C#语言中的结构体

通过使用属性可以自定义结构在内存中的布局方式例如可以使用 StructLayout(LayoutKindExplicit) 和 FieldOffset 属性创建在 C/C++ 中称为联合的布局

[SystemRuntimeInteropServicesStructLayout(LayoutKindExplicit)]

struct TestUnion

{

[SystemRuntimeInteropServicesFieldOffset()]

public int i;

[SystemRuntimeInteropServicesFieldOffset()]

public double d;

[SystemRuntimeInteropServicesFieldOffset()]

public char c;

[SystemRuntimeInteropServicesFieldOffset()]

public byte b;

}

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

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

[SystemRuntimeInteropServicesStructLayout(LayoutKindExplicit)]

struct TestExplicit

{

[SystemRuntimeInteropServicesFieldOffset()]

public long lg;

[SystemRuntimeInteropServicesFieldOffset()]

public int i;

[SystemRuntimeInteropServicesFieldOffset()]

public int i;

[SystemRuntimeInteropServicesFieldOffset()]

public double d;

[SystemRuntimeInteropServicesFieldOffset()]

public char c;

[SystemRuntimeInteropServicesFieldOffset()]

public byte b;

}

i 和 i 这两个 int 字段共享与 lg 相同的内存位置使用平台调用时这种结构布局控制很有用

我做了一个简单的测试程序基本达成预定需求不过程序该方式要求比较苛刻如果要解析的数据与转换的结构体不匹配就会引发一系列莫名其妙的异常(如内存不可读等等之类)下面是测试程序的源代码有兴趣的朋友可以看一看也希望网友能提出更好的方案

using System;

using SystemCollectionsGeneric;

using SystemComponentModel;

using SystemData;

using SystemDrawing;

using SystemText;

using SystemWindowsForms;

using SystemIO;

using SystemRuntimeInteropServices;

namespace RWFile

{

public partial class Form : Form

{

public Form()

{

InitializeComponent();

}

//从文件中读结构体

private void button_Click(object sender EventArgs e)

{

string strFile = ApplicationStartupPath + \\testdat;

if (!FileExists(strFile))

{

MessageBoxShow(文件不存在);

return;

}

FileStream fs = new FileStream(strFile FileModeOpen

FileAccessReadWrite);

TestStruct ts = new TestStruct();

byte[] bytData = new byte[MarshalSizeOf(ts)];

fsRead(bytData bytDataLength);

fsClose();

ts = rawDeserialize(bytData);

textBoxText = tsdTestToString();

textBoxText = tsuTestToString();

textBoxText = EncodingDefaultGetString(tsbTest);

}

//向文件中写结构体

private void button_Click(object sender EventArgs e)

{

string strFile = ApplicationStartupPath + \\testdat;

FileStream fs = new FileStream(strFile FileModeCreate

                                           FileAccessWrite);

TestStruct ts = new TestStruct();

tsdTest = doubleParse(textBoxText);

tsuTest = UIntParse(textBoxText);

tsbTest = EncodingDefaultGetBytes(textBoxText);

byte[] bytData = rawSerialize(ts);

fsWrite(bytData bytDataLength);

fsClose();

}

[StructLayout(LayoutKindSequentialCharSet = CharSetAnsi)] //Size=

public struct TestStruct

{

[MarshalAs(UnmanagedTypeR)] //FieldOffset()]

public double dTest;

[MarshalAs(UnmanagedTypeU)] // FieldOffset()]

public UInt uTest;

[MarshalAs(UnmanagedTypeByValArray SizeConst = )]

                                  // FieldOffset()]

public byte[] bTest;

}

//序列化

public static byte[] rawSerialize(object obj)

{

int rawsize = MarshalSizeOf(obj);

IntPtr buffer = MarshalAllocHGlobal(rawsize);

MarshalStructureToPtr(obj buffer false);

byte[] rawdatas = new byte[rawsize];

MarshalCopy(buffer rawdatas rawsize);

MarshalFreeHGlobal(buffer);

return rawdatas;

}

//反序列化

public static TestStruct rawDeserialize(byte[] rawdatas)

{

Type anytype = typeof(TestStruct);

int rawsize = MarshalSizeOf(anytype);

if (rawsize > rawdatasLength) return new TestStruct();

IntPtr buffer = MarshalAllocHGlobal(rawsize);

MarshalCopy(rawdatas buffer rawsize);

object retobj = MarshalPtrToStructure(buffer anytype);

MarshalFreeHGlobal(buffer);

return (TestStruct)retobj;

}

}

}

               

上一篇:C#附加数据库

下一篇:了解C#特性匿名类型与隐式类型局部变量