熱點推薦:
您现在的位置: 電腦知識網 >> 編程 >> .NET編程 >> 正文

探析C#文件方式讀寫結構體

2013-11-13 09:56:41  來源: .NET編程 

  最近一直在研究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;
}      
}
}


From:http://tw.wingwit.com/Article/program/net/201311/12072.html
  • 上一篇文章:

  • 下一篇文章:
  • 推薦文章
    Copyright © 2005-2013 電腦知識網 Computer Knowledge   All rights reserved.