[RESOLVED] Reading a structure from a file.
I have several quesions about reading/writing structures from/to files.
In a scenario when I open a data file having its own header and variable data fields I create a structure that represents a header consisting of 9 bytes:
Code:
Public Structure HeaderInfo
Public DataField1 As Integer
Public DataField2 As Byte
Public DateField3 As Integer
End Structure
I'm using this code for the time being:
vb.net Code:
Public Function ReadHeader(ByVal FileName As String) As HeaderInfo
Dim ReturnInfo As HeaderInfo
Try
Using br As New IO.BinaryReader(New IO.FileStream(FileName, IO.FileMode.Open, IO.FileAccess.Read, IO.FileShare.Read))
With ReturnInfo
.DataField1 = br.ReadInt32()
.DataField2 = br.ReadByte()
.DataField3 = br.ReadInt32()
End With
br.Close()
End Using
Return ReturnInfo
Catch ex As Exception
Return Nothing
End Try
End Function
The first question is - can I fill the structure directly somehow? Some structures are very long and filling them this way will be tedious. For example, if I know the length of the structure I could read the needed number of bytes in a byte array and somehow marshal these bytes into the structure.
My second question:
I can use Marshal.PtrToStructure, but then I would need to get an IntPtr of my byte array. Is it the only option?
And the last question - I use <Serializable()> attribute for my structure. Am I doing it right? Should there be some other attributes?
Re: Reading a structure from a file.
That would have been much easier in C++ ;) I'm afraid there's no simple solution for this problem, well at least no simple solution known to me.
Here's a post about that issue, it might help at least a little.
good luck
Re: Reading a structure from a file.
If you've got the Serializable tag on your structure...then yes, you are doing it the hard way and not taking advantage of that tag.
Here's one example:
http://www.vbforums.com/showthread.p...=serialization
It's using XML serialization.
doing binary serialization is just as easy, all you need is a binary stream instead of an xml one.
In fact, if you do a search here in the VS2005/2008/2010 forums for "serialization" you'll find a ton of threads and examples.
-tg
Re: Reading a structure from a file.
Well, I've changed the function like this:
Code:
Public Function GetCellInfo(ByVal Offset As Long) As CellInfo
Using br As New IO.BinaryReader(New IO.FileStream(_filename, IO.FileMode.Open, IO.FileAccess.Read, IO.FileShare.Read))
br.BaseStream.Position = Offset
Dim bytes() = br.ReadBytes(32)
Dim handle As IntPtr = Marshal.ReadIntPtr(bytes, 0)
Dim ci As New CellInfo
Marshal.PtrToStructure(handle, ci)
If _header.FormatVersion = 6 Then
ci.TextRotation = 0
End If
Return ci
End Using
End Function
The structure length is 32 bytes and I use these attributes.
Code:
<StructLayout(LayoutKind.Sequential), Serializable()> _
Public Structure CellInfo
' ...
End Structure
Didn't test it though, so I don't know whether it works.
Re: Reading a structure from a file.
Do you want to use the fairly simple serialization or do you want to continue to push the data in and out of the file your own way?
Simple binary serialization....
Code:
Dim someClassOfMine As New TestClass1
Dim formatter As New Runtime.Serialization.Formatters.Binary.BinaryFormatter
Dim myWriter As New IO.FileStream("arrayTest.bin", IO.FileMode.Create)
formatter.Serialize(myWriter, someClassOfMine)
myWriter.Close()
Use your structure instead of the class I used...
And to deserialize...
Code:
Dim formatter As New Runtime.Serialization.Formatters.Binary.BinaryFormatter
Dim fs As New IO.FileStream("arrayTest.bin", IO.FileMode.Open)
someClassOfMine = DirectCast(formatter.Deserialize(fs), TestClass1)
fs.Close()
-tg
Re: Reading a structure from a file.
No, I don't think this is the case of mine.
The file I try to open is a custom spreadsheet format. It hold the following structures:
Header ' Fixed length
General Cell Format ' Fixed length
Font Table ' Variable Length
Page Header ' Fixed length
Pfge Footer ' Fixed Length
Columns definitions ' Variable length
Rows definitions ' Variable length
Rows data ' variable length
Groups definitions ' Variable length
Range names ' Variable length
So I doublt I can use your example.
Re: Reading a structure from a file.
That sound you are hearing is me banging my head into the desk. It's that kind of info that's needed in the first post so that you don't get a bad answer. Since that is the case... serialization does you zero good, and there's no point in having the Serialization mark up. It also means you are basically relegated to using your current brute force method (of which there isn't anything inherently wrong with). But like you mentioned, it can be tedious.
-tg
Re: Reading a structure from a file.
Quote:
Originally Posted by
techgnome
That sound you are hearing is me banging my head into the desk. It's that kind of info that's needed in the first post so that you don't get a bad answer. Since that is the case... serialization does you zero good, and there's no point in having the Serialization mark up. It also means you are basically relegated to using your current brute force method (of which there isn't anything inherently wrong with). But like you mentioned, it can be tedious.
-tg
Oddly enought I'm not hearing any sounds right now :)
Well, the question gradually transforms into 'How can I cast a byte array into a structure and back?' I've no chance to test the code from my post #4 right now but if it works I think the matter is resolved. Unfortunately I would be able to test it only tomorrow morning ))) If this method fails I'm thinking of resorting to the CopyMemory API function.
Re: Reading a structure from a file.
It's tedious?
That's what With is for. Just use the simple way, and keep the code readable.
Re: Reading a structure from a file.
It's still 200 lines of code for 200 fields... that's where the tedium is.
-tg
Re: Reading a structure from a file.
Finally got it working:
vb.net Code:
Dim bytes() = br.ReadBytes(60) ' Reading 60 bytes from the file
Dim handle As IntPtr
Dim gch = GCHandle.Alloc(bytes, GCHandleType.Pinned) ' Allocating a handle to unmanaged memory area
handle = gch.AddrOfPinnedObject ' Obtaining a pointer to it
' Filling the structure:
Dim lf As LOGFONT = CType(Marshal.PtrToStructure(handle, GetType(LOGFONT)), LOGFONT)
' Releasing the handle
gch.Free()
Logfont structure:
Code:
<StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Ansi)> _
Public Structure LOGFONT
Public lfHeight As UInt32 ' 4 bytes (offset 0)
Public lfWidth As UInt32 ' 4 bytes (offset 4)
Public lfEscapement As UInt32 ' 4 bytes (offset 8)
Public lfOrientation As UInt32 ' 4 bytes (offset 12)
Public lfWeight As UInt32 ' 4 bytes (offset 16)
Public lfItalic As Byte ' 1 byte (offset 20)
Public lfUnderline As Byte ' 1 byte (offset 21)
Public lfStrikeOut As Byte ' 1 byte (offset 22)
Public lfCharSet As Byte ' 1 byte (offset 23)
Public lfOutPrecision As Byte ' 1 byte (offset 24)
Public lfClipPrecision As Byte ' 1 byte (offset 25)
Public lfQuality As Byte ' 1 byte (offset 26)
Public lfPitchAndFamily As Byte ' 1 byte (offset 27)
<MarshalAs(UnmanagedType.ByValTStr, SizeConst:=32)> _
Public lfFaceName As String ' 32 bytes(offset 28) total 60 bytes
End Structure