VB.NET中将结构体保存到文件的方法

前端之家收集整理的这篇文章主要介绍了VB.NET中将结构体保存到文件的方法前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
VB.NET中的结构体在使用的时候像是一个“小型的类”,其内部结构与VB6.0相比有许多不同。当需要把一个VB6.0中的结构体升级到对应的.NET版本时,在细节上会有很多区别。

前段时间,在将一个6.0的程序升级到.NET的过程中就遇到了很多麻烦。这个结构体中包含了定长字符串、数组以及其它一些结构,需要将该结构体作为头文件直接保存到一个二进制文件中,同时还要能从文件中读出该结构体。在6.0中,该结构体如下:

  1. TypeOptionType
  2. IDAsString*11
  3. SamplingModeAsInteger
  4. StartModeAsByte
  5. FreqAsInteger
  6. TimeAsSingle
  7. PreTimeAsLong
  8. SamplesAsLong
  9. TestNameAsString*24
  10. Chan(1ToADCOCHANS)AsChanType
  11. TimeUnitAsInteger
  12. VectorUSpanAsSingle
  13. VectorISpanAsSingle
  14. RelatAsString*20
  15. AddrAsString*20
  16. TestDateAsDate
  17. TestMemoAsString*320
  18. EndType

其中,ChanType是另一个结构体,如下:

  • TypeChanType
  • ChanNoAsString*10
  • ChanNameAsString*10
  • UnitAsString*6
  • OffonAsInteger
  • RatioAsSingle
  • FactorAsSingle
  • DcacAsInteger
  • LowerAsSingle
  • UpperAsSingle
  • ZeroValAsSingle
  • ColorAsLong
  • ShiftAsInteger
  • EndType
  • 如果只是简单的将其改写到.NET版本并不难,但若想在.NET中读出以前6.0下保存的二进制文件时,就需要好好的设计一番了。具体涉及到以下几个问题:

    1、.NET中已不再直接支持6.0中的定长字符串。不定长的字符串在存储时,需要同时存储一个长度值。

    2、.NET中的数据类型有了很大变化,比如Integer是从16位变为32位,DateTime以整数形式保存而不再是以前的Double型

    。。。

    在此不一一列举,有兴趣的可以参看微软出的相关文档。下面是改写后的结构体:

  • <StructLayoutAttribute(LayoutKind.Sequential,CharSet:=CharSet.Ansi,Pack:=1)>_
  • PublicStructureStructOption
  • <MarshalAs(UnmanagedType.ByValTStr,SizeConst:=11)>_
  • PublicIDAsString
  • PublicSamplingModeShort
  • PublicStartModeByte
  • PublicFreqPublicTimeSingle
  • PublicPreTimeInteger
  • PublicSamplesInteger
  • <MarshalAs(UnmanagedType.ByValTStr,SizeConst:=24)>_
  • PublicTestNameString
  • <MarshalAs(UnmanagedType.ByValArray,SizeConst:=44)>_
  • PublicChan()AsStructChan
  • PublicTimeUnitPublicVectorUSpanPublicVectorISpanSingle
  • <MarshalAs(UnmanagedType.ByValTStr,SizeConst:=20)>_
  • PublicRelatString
  • PublicAddrPublicTestDateDate
  • <MarshalAs(UnmanagedType.ByValTStr,SizeConst:=320)>_
  • PublicTestMemoString
  • SharedFunctionCreateInstance()AsStructOption
  • DimretNewStructOption
  • DimnewChanNewStructChan
  • ReDimret.Chan(ADCOCHANS-1)
  • ForiInteger=0ToADCOCHANS-1
  • ret.Chan(i)=newChan
  • Next
  • Returnret
  • EndFunction
  • Structure
  • StructureStructChan
  • <MarshalAs(UnmanagedType.ByValTStr,SizeConst:=10)>_
  • PublicChanNoString
  • <MarshalAs(UnmanagedType.ByValTStr,153); background-color:inherit">PublicChanNamePublicUnitPublicOffonPublicRatioPublicfactorPublicDcacShort
  • PublicLowerPublicUpperPublicZeroValPublicColorInteger
  • PublicShiftStructure
  • 或许你已经注意到了,在改写的结构体中使用了一些属性,必须使用这些属性,才能构造出与VB6一模一样的结构体(至少说保存到文件中时时一样的结构)。

    .NET中将结构体保存至文件方法有两种:

    一种是为结构体添加<Serializable()>属性,然后使用System.Runtime.Serialization.Formatters.Binary.BinaryFormatter中的Serialize方法将其串行化为文件流,并可用Deserialize方法将其还原为结构体;

    另一种方法便是本文要讨论的,即结构体与字节数组之间的转化,因为在VB6中保存结构体时是按字节存储的,要做到同样效果需要将结构体其转化为字节数组。

    再回到改写后的结构体中,为了定义属性,首先需要导入命名空间

    Imports System.Runtime.InteropServices

    接下来的结构体属性必不可少:

    <StructLayoutAttribute(LayoutKind.Sequential,CharSet:=CharSet.Ansi,Pack:=1)>

    对于定长字符串,需要添加如下属性
    <MarshalAs(UnmanagedType.ByValTStr,SizeConst:=11)>

    注意,这里,字符串只能保存10个字符

    对于定长数组,同样需要添加属性

    <MarshalAs(UnmanagedType.ByValArray,SizeConst:=44)>

    另外,在使用前,需要对定长数组的长度进行ReDim,且长度必须与SizeConst相等。事实上,如果你定义了更长的长度,它会只截取SizeConst长度进行保存

    接下来便是结构体与字节数组之间的转化,以及从文件读取结构体的源代码(注:部分源码根据网络上的C#版本改写)

  • PrivateSubStructToBytes(ByValobjStructObject,ByRefbytes()Byte)
  • '得到结构体长度
  • DimsizeInteger=Marshal.SizeOf(objStruct)
  • '重新定义数组大小
  • ReDimbytes(size)
  • '分配结构体大小的内存空间
  • DimptrStructAsIntPtr=Marshal.AllocHGlobal(size)
  • '将结构体放入内存空间
  • Marshal.StructureToPtr(objStruct,ptrStruct,False)
  • '将内存拷贝到字节数组
  • Marshal.Copy(ptrStruct,bytes,size)
  • '释放内存空间
  • Marshal.FreeHGlobal(ptrStruct)
  • Sub
  • '''<summary>
  • '''字节数组bytes()转化为结构体
  • FunctionBytesToStruct(Byte,153); background-color:inherit">ByValmytypeAsType)Object
  • '获取结构体大小
  • Integer=Marshal.SizeOf(mytype)
  • 'bytes数组长度小于结构体大小
  • If(size>bytes.Length)Then
  • '返回空
  • ReturnNothing
  • If
  • '将数组拷贝到内存
  • Marshal.Copy(bytes,0); background-color:inherit">'将内存转换为目标结构体
  • DimobjObject=Marshal.PtrToStructure(ptrStruct,mytype)
  • '释放内存
  • Marshal.FreeHGlobal(ptrStruct)
  • Returnobj
  • Function
  • '''从文件中读取结构体
  • '''</summary>
  • '''<returns>结构体</returns>
  • '''<remarks></remarks>
  • FunctionFileToStruct(ByValstrPathString,0); background-color:inherit">'获得结构体大小
  • '打开文件
  • DimfsNewFileStream(strPath,FileMode.Open)
  • '读取size个字节
  • Dimbytes(size)Byte
  • fs.Read(bytes,0); background-color:inherit">'将读取的字节转化为结构体
  • Object=BytesToStruct(bytes,248); margin:0px!important; padding:0px 3px 0px 10px!important"> fs.Close()
  • Function
  • 猜你在找的VB相关文章