探析C#檔案方式讀寫結構體

來源:互聯網
上載者:User
最近一直在研究。Net Micro Framework字型檔(tinyfnt),由於tinyfnt檔案頭部有一段描述資料,所以很想定義一個結構體,像VC一樣直接從檔案中讀出來,省得用流一個個解析很是麻煩。

  沒有想到在C#中竟沒有直接的指令,想必C#設計者認為提供了流和序列化技術,一切問題都可以迎刃而解了。

  在C#中結構體是一個比較複雜的東西,在此之上有很多需要設定的參數,否則用起來就很容易出錯。下面是msdn上一段描述,看看也許有助於理解C#語言中的結構體。

  通過使用屬性可以自訂結構在記憶體中的布局方式。例如,可以使用 StructLayout(LayoutKind.Explicit) 和 FieldOffset 屬性建立在 C/C++ 中稱為聯合的布局。

[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 的所有欄位都從記憶體中的同一位置開始。

  以下是欄位從其他顯式設定的位置開始的另一個樣本。

[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 相同的記憶體位置。使用平台叫用時,這種結構布局控制很有用。

  我做了一個簡單的測試程式,基本達成預定需求,不過程式該方式要求比較苛刻,如果要解析的資料與轉換的結構體不匹配就會引發一系列莫名其妙的異常(如記憶體不可讀等等之類),下面是測試程式的原始碼,有興趣的朋友可以看一看,也希望網友能提出更好的方案。

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,CharSet = 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;
}      
}
}

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.