`
lovecontry
  • 浏览: 1095123 次
文章分类
社区版块
存档分类
最新评论

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

 
阅读更多

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

}

}

}

分享到:
评论

相关推荐

    OPCUA读写结构体示例

    在这个示例中,我们将关注如何使用C#语言来读写OPCUA服务器上的复杂结构体。 首先,理解OPCUA中的结构体是非常重要的。结构体是OPCUA数据类型系统的一部分,允许定义自定义的数据模型,这些模型可以包含多个基础...

    C#从文件中存储及读取结构体示例

    总结,C#中存储和读取结构体到二进制文件的关键在于使用`BinaryFormatter`进行序列化和反序列化。理解这个过程对于处理数据持久化、数据传输等任务至关重要。当然,选择合适的序列化方法还需根据具体需求,考虑性能...

    结构体序列化读写二进制文件类

    在IT领域,结构体序列化和二进制文件读写是常见的数据存储和传输技术。这类技术主要用于将复杂的结构化数据转换成二进制格式,以便于高效地存储到磁盘或在网络上传输。以下是对"结构体序列化读写二进制文件类"这一...

    c++调用C# COM 参数是结构体数组

    在 C# 中,结构体数组是使用数组类型来定义的,如 `_CAPI_Point3d[] tst = new _CAPI_Point3d[count];`。在这个例子中,我们定义了一个 _CAPI_Point3d 结构体数组,数组长度为 count。 Marshal 类 在 C# 中,...

    QT使用结构体生成读写配置文件数据代码

    在实际项目中,可能有多个结构体需要读写配置文件,此时可以创建一个通用的函数,如`readStruct(QSettings&, T&)`和`writeStruct(QSettings&, const T&)`,利用模板编程实现对不同结构体的读写操作。 最后,`001_...

    C++结构体/函数定义转换C#函数定义/结构体

    本文将深入探讨如何将C++的结构体、数据类型和函数定义转换为C#,并结合提供的文件列表,讨论可能涉及的工具和技术。 首先,C++和C#虽然都是面向对象的编程语言,但在语法和类型系统上有显著差异。C++支持模板、...

    Codesys读写结构体保存到本地文件

    Codesys读写结构体保存到本地文件

    C#遍历结构体

    在本篇文章中,我们将深入探讨如何在C#中遍历结构体,并理解代码片段中的具体实现方式。通过本文,读者可以全面了解C#语言中如何处理结构体成员,并掌握使用反射来获取和操作结构体属性的方法。 ### C#中结构体的...

    C#byte数组结构体互相转换示例.zip

    在C#编程中,结构体(Struct)与字节数组(Byte Array)之间的转换是一项常见的操作,特别是在处理网络通信、序列化或低级数据处理时。本示例提供了便捷的方法来实现这种转换,帮助开发者解决相关的技术难题。 首先...

    C#调用C++ Dll关于结构体数组引用的传递及解析使用的展示代码

    使用`StructLayout`属性指定结构体布局,并通过`MarshalAs`属性指定字符数组的存储方式。这里的`MarshalAs`属性特别重要,因为它确保了字符数组在内存中的正确布局。 #### C#中调用DLL C#中调用C++ DLL的关键在于...

    调用示例.rar_C#调用c++ dll_C#调用函数指针_C#调用结构体_结构体_调用C dll

    C#调用C++ dll, 包括结构体, 数组, 函数指针, 字符串等等

    向文件写结构体,或从文件读取结构体 VC

    如果结构体中包含C++特有的类型(如指针或动态分配的数组),那么直接读写可能会出现问题,因为它们在内存中可能不是连续的。此时,需要自定义序列化和反序列化逻辑。 在实际开发中,除了基本的结构体,我们还可能...

    C#调用C++结构体开发

    在IT行业中,跨语言通信是常见的需求之一,特别是在Windows平台上,C#和C++的混合编程经常被用于利用C++的高性能和C#的高级特性。...通过这种方式,开发者可以在C#的高生产力环境中利用C++的底层性能,实现复杂的功能。

    C# 结构体与数组转换,结构体成员支持数组类型

    C#实现结构体与数组间的转换,包括:同时支持大小端;支持自定义数据类型;支持数组类型结构体成员,带单元测试

    C#结构体指针的定义及使用详解

    C#结构体可以通过以下方式定义: ```csharp [StructLayout(LayoutKind.Sequential)] public struct VGAStat { public int ChannelNum; // 通道数量 [MarshalAs(UnmanagedType.ByValArray, SizeConst = 64)] ...

    C#中byte数组和c++结构体的转换

    在写C#TCP通信程序时,发送数据时,只能发送byte数组,处理起来比较麻烦不说,如果是和c++等写的程序通信的话,很多的都是传送结构体,在VC6.0中可以很方便的把一个char[]数组转换为一个结构体,而在C#却不能直接把...

    C#共享内存传递结构体数据

    C#共享内存传递结构体数据

    基于C#调用c++Dll结构体数组指针的问题详解

    基于C#调用C++ Dll结构体数组指针的问题详解 C#调用C++ Dll文件是一件很麻烦的事情,首先面临的是数据类型转换的问题。相信经常做C#开发的都和...C#调用C++ Dll文件需要注意数据类型的转换和结构体数组的申明和使用。

    C# 读写欧姆龙PLC Fins,C#读写Omron上位机 全开源项目 Omron 上位机快速开发 c#快速开发欧姆龙PLC下载

    C# 读写欧姆龙PLC Fins,C#读写Omron PLC 全开源项目 使用一个开源的技术来读写欧姆龙PLC数据,使用的是基于以太网的TCP/IP实现,不需要额外的组件,读取操作只要放到后台线程就不会卡死线程,本组件支持超级方便的...

    C#类最初步代码结构体创建

    在提供的`CreateStruct`文件中,可能包含了用于练习或学习的结构体创建示例。通过查看和理解这些代码,你可以进一步巩固C#中结构体创建和使用的知识。 总之,C#的结构体是一种轻量级的数据结构,适用于简单数据的...

Global site tag (gtag.js) - Google Analytics