處理 .NET Micro Framework 字型檔(tinyfnt)時,檔頭包含固定結構描述資料。期望像 C/C++ 直接將檔案內容讀入結構體,避免逐欄位解析。然而 C# 無直接指令支援,需結合 StructLayout、Marshal 類別實現。
透過屬性自訂結構在記憶體中的排列:
[StructLayout(LayoutKind.Explicit)]
struct TestUnion
{
[FieldOffset(0)] public int i;
[FieldOffset(0)] public double d;
[FieldOffset(0)] public char c;
[FieldOffset(0)] public byte b;
}
// 所有欄位共用相同記憶體位址,類似 C++ union
[StructLayout(LayoutKind.Explicit)]
struct TestExplicit
{
[FieldOffset(0)] public long lg;
[FieldOffset(0)] public int i1;
[FieldOffset(4)] public int i2;
[FieldOffset(8)] public double d;
[FieldOffset(12)] public char c;
[FieldOffset(14)] public byte b;
}
// 明確指定每個欄位偏移量
平台呼叫(P/Invoke)時此類控制極為重要。
using System;
using System.IO;
using System.Runtime.InteropServices;
namespace RWFile
{
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct TestStruct
{
[MarshalAs(UnmanagedType.R8)] public double dTest;
[MarshalAs(UnmanagedType.U2)] public UInt16 uTest;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)] public byte[] bTest;
}
public static class StructIO
{
// 序列化:結構體 → byte[]
public static byte[] RawSerialize(object obj)
{
int size = Marshal.SizeOf(obj);
IntPtr ptr = Marshal.AllocHGlobal(size);
Marshal.StructureToPtr(obj, ptr, false);
byte[] data = new byte[size];
Marshal.Copy(ptr, data, 0, size);
Marshal.FreeHGlobal(ptr);
return data;
}
// 反序列化:byte[] → 結構體
public static T RawDeserialize(byte[] data) where T : struct
{
int size = Marshal.SizeOf(typeof(T));
if (size > data.Length) return default;
IntPtr ptr = Marshal.AllocHGlobal(size);
Marshal.Copy(data, 0, ptr, size);
object obj = Marshal.PtrToStructure(ptr, typeof(T));
Marshal.FreeHGlobal(ptr);
return (T)obj;
}
}
// 使用範例
class Program
{
static void Main()
{
string path = "test.dat";
// 寫入
TestStruct ts = new TestStruct { dTest = 3.14, uTest = 42, bTest = System.Text.Encoding.Default.GetBytes("Hello") };
File.WriteAllBytes(path, StructIO.RawSerialize(ts));
// 讀取
TestStruct ts2 = StructIO.RawDeserialize(File.ReadAllBytes(path));
Console.WriteLine($"dTest={ts2.dTest}, uTest={ts2.uTest}, bTest={System.Text.Encoding.Default.GetString(ts2.bTest)}");
}
}
}
LayoutKind.Sequential 依宣告順序配置,配合 MarshalAs 指定非受控型別對應。ByValArray 固定大小(SizeConst)。