Reading a binary file with VB.NET

Posted on 2006-05-31
Medium Priority
Last Modified: 2012-05-05
Let's try this again, a little more concisely:

I am trying to convert some code from VB6.0 to VB.NET, this particular loop populates a data structure from a binary file, and I am having a huge problem getting equivalent results.  I'll cut and paste the old code and new code below, and if anyone can tell me what I'm doing wrong, or (even better!) give me a couple of snippets, I'd be eternally graceful!  

The problems are in the GetVariable function of the second section.  Just pasted the rest for completeness.  Part of the problem this isn't simple is because the BinaryReader doesn't seem to support random access... but I'm not married to it.


old, working VB6.0 code

Private Type XVDataType

    sText As String * 50
    iNumPoints As Integer
    dData(50) As Double

End Type

Private Sub ButtonGo_Click()
     Dim X as XVDataType

     Dim f as String
     f = "C:\Documents and Settings\crice\My Documents\Active Tasks\TCFLO\Project\TCFLO\TCFLO.rst"

     X = GetVariable(f, 4)    ' calls the getvariable function with some dummy data, to test

End Sub

Private Function GetVariable(sRestartFile As String, iNumXVar As Integer) As XVDataType

    ' inumvar is 1-based
    Dim XV As XVDataType

    ' get the variable definitions
    Dim ind As Long
    Open sRestartFile For Binary As #1
    ind = 254  ' header offset

    Get #1, ind + (iNumXVar - 1) * 508 + 1, XV.iNumPoints
    Dim n As Integer
    For n = 0 To XV.iNumPoints - 1
        Get #1, ind + (iNumXVar - 1) * 508 + 9 + n * 8, XV.dData(n)
    Next n
    Get #1, ind + (iNumXVar - 1) * 508 + 459, XV.sText

    GetRestartExternalVariable = XV
    ' close the file and exit
    Close #1
    Exit Function

End Function

new, mostly not working VB.NET code

    Private Sub Button4_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button4.Click

        Call GetVariable( _
        "C:\Documents and Settings\crice\My Documents\Active Tasks\TCFLO\Project\TCFLO\TCFLO.rst" _
        , 4)

    End Sub

    Private Function GetVariable(ByVal sRestartFile As String, ByVal iNumXVar As Integer) As XVDataType

        Dim XV As New XVDataType

        ' get the variable definitions
        Dim ind As Long = 254   ' header offset

        If System.IO.File.Exists(sRestartFile) Then

            Dim binReader As New System.IO.BinaryReader(File.Open(sRestartFile, FileMode.Open))
            binReader.ReadBytes(ind + (iNumXVar - 1) * 508)
            XV.iNumPoints = binReader.ReadByte()     ' <---- THIS WORKS, gets the right number of points
            For n As Integer = 0 To XV.iNumPoints - 1

                XV.dData(n) = binReader.ReadSingle    ' <---- this doesn't work worth a darn
                'XV.dData(n) = binReader.ReadDouble    '    <------ this didn't work either
                'binReader.ReadBytes(8)                         '    < ------ nor this        
                'Get #1, ind + (iNumXVar - 1) * 508 + 9 + n * 8, XV.dData(n)   ' <------- the equivalent VB6.0 code

            Next n

            XV.sText = binReader.ReadChars(10)      ' <------ doesn't work


        End If

    End Function
Question by:riceman0
LVL 11

Expert Comment

ID: 16804607
DO you get an error message?
Does the binReader.Position  change after the readByte..?
Does the ReadByte work instead of the ReadSingle at the first problem.?
LVL 34

Accepted Solution

Sancler earned 2000 total points
ID: 16805745
Your structure definition suggests that the data would be saved in the order sText (String - fixed length 50), then iNumPoints (Integer), then dData (Double * 51).  But your code appears to read the data in the order INumPoints, then dData, then sText.  I'm assuming that it is the latter that is correct.

That iNumPoints is in fact the first data saved in the file structure appears to be confirmed by the fact that your VB.NET code is OK up to this point

            XV.iNumPoints = binReader.ReadByte()     ' <---- THIS WORKS, gets the right number of points

But what you are reading is a Byte whereas what your structure appears to contain is an Integer.  An Integer, depending on its type, will be 2-, 4- or 8-bytes.  What you have read is the first 4 BITS of the data, which happens to give you the right value.  But the BinaryReader's position has only been advanced by one byte whereas the next data does not begin until after the 2-, 4- or 8-byte boundary.  So any subsequent read is going to start at the wrong place.  Which is why, I think, none of your attempts to read the next data worked.  What you need to do first, I think, is replace

            XV.iNumPoints = binReader.ReadByte()


            XV.iNumPoints = binReader.ReadInt16()
            XV.iNumPoints = binReader.ReadInt32()
            XV.iNumPoints = binReader.ReadInt64()

as appropriate - most probably ReadInt32 as in VB.NET the default for Integer datatype is Int32.

Then the binReader pointer should be properly aligned for starting to read the dData.  The datatype of that is Double, so

                XV.dData(n) = binReader.ReadDouble

should be the right call for that.

You will, however, even if that is OK, have trouble with the VB.NET code when you get to reading sText.  This is because you are only reading - and therefore advancing binReader's pointer by - the number of Doubles that is in iNumPoints and not by the full length of the stored Array(50) of Doubles.  In your VB6 code you calculated the precise position at which the sText data would begin, but in your VB.NET code you are assuming it will start immediately after iNumPoints * Double.  But it won't (except in the case where iNumPoints = 51).  So you will need to revise your loop so that it reads 51 times (to advance the binReader pointer enough), but only stores the data in your structure until iNumPoints is reached.

I reckon that with modifications on the above lines, your VB.NET function should work with a BinaryReader.  But an alternative approach you might like to think about is reading the whole of your file into a byte array and then extracting the individual structures from that using a similar offset calculation approach as you do in your VB6 code.  Or, you could more or less "port" your VB6 code to VB.NET by using the FileGet method instead of Get #.

Incidentallly, your VB.NET Function doesn't return anything, but I assume that is because it is for test purposes, rather than for real.


LVL 34

Expert Comment

ID: 16805824
What you have read is the first 4 BITS of the data ...

should be

What you have read is the first BYTE of the data ...

LVL 86

Expert Comment

by:Mike Tomlinson
ID: 16807014
Roger brings up a good point about the size of Ints being different in VB.Net.

Important questions:

    Are you reading the OLD file created by VB6?

    ...or are you attempting to read a NEW file that was created by VB.Net code with new .Net types (and consequently new different sizes)?

Have you considered using XML or possibly Binary Serialization instead of Structures?

Author Comment

ID: 16807326

To answer the questions:

* no error messages, just wrong values
* correct, the data in the file is not ordered like the order of the structure -- maybe a little misleading; it is # points, data, text
* the VB.NET class is reading the exact same file as the VB6.0 class, they were both produced by the same ancient DOS program that this is post-processing  :)

I will try the suggestions in the next couple of hours, thanks!

Featured Post

Free Tool: Path Explorer

An intuitive utility to help find the CSS path to UI elements on a webpage. These paths are used frequently in a variety of front-end development and QA automation tasks.

One of a set of tools we're offering as a way of saying thank you for being a part of the community.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Introduction As chip makers focus on adding processor cores over increasing clock speed, developers need to utilize the features of modern CPUs.  One of the ways we can do this is by implementing parallel algorithms in our software.   One recent…
Parsing a CSV file is a task that we are confronted with regularly, and although there are a vast number of means to do this, as a newbie, the field can be confusing and the tools can seem complex. A simple solution to parsing a customized CSV fi…
In a question here at Experts Exchange (https://www.experts-exchange.com/questions/29062564/Adobe-acrobat-reader-DC.html), a member asked how to create a signature in Adobe Acrobat Reader DC (the free Reader product, not the paid, full Acrobat produ…
With just a little bit of  SQL and VBA, many doors open to cool things like synchronize a list box to display data relevant to other information on a form.  If you have never written code or looked at an SQL statement before, no problem! ...  give i…
Suggested Courses

829 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question