Mark Worsnop
Mark Worsnop

Reputation: 4467

Converting byte array to single from binary file

UPDATED - I added 2 screen shots with 0.00 in the data and one with 1234.56 in the data

I am using an old VB6 set of code as 95% works to read a text file that gets converted and stored in MS SQL. The strings are all good however there are numbers mixed into the text binary file that I haven't figured out how to read. The original application the numbers are all currency however the hex dump of the numbers looks to be 4 byte numbers.

Either way I am not sure how to read the numbers into a local variable. Maybe I am not starting at the correct place in the data. In the example below I am starting at the <160>.

Here is a dump of the part of the binary file with 0.00 in the data:

enter image description here

Here is a dump of the part of the binary file with 1234.56 in the data:

enter image description here

Note the arrow point to where the data changed.

This is my last try but that doesnt work either.

Function ReadFloat(f As Integer, Optional ShowDB As Boolean = False) As String
    On Error GoTo 0

  Dim c As Single
  Dim S(4) As Byte
   Dim x As Integer
   Dim flt As Single


  Get f, , S

   For x = 1 To 4
    Debug.Print x & "  " & S(x) & "   " & Hex(S(x)); "='" & Chr(S(x)) & "'"

   Next x

   CopyMemory flt, S, 4

Upvotes: 0

Views: 1453

Answers (2)

Guillermo Phillips
Guillermo Phillips

Reputation: 2216

My initial inspection suggests that the bytes starting:

40 E2 01

are what you're looking for. These are stored little endian, so 01E240 is hex for 123456 in decimal. So my guess would be 32 bit integers (4 byte long type). You can test this by using -0.01 as a value, this should give:

... FF FF FF FF ...

in the file.

If you're only interested in reading just these values then you can read and discard the first x values. Something like:

Dim yDiscard(123) As Byte
...
Get #1, ,yDiscard

Or alternatively, just seek to the position first before reading:

Seek #1, 123

To work out what byte values to expect in general, I found the following to be useful. Just run the code in a module:

Sub main()
    Dim lValue As Long
    Dim cValue As Currency
    Dim nValue As Single
    Dim dValue As Double
    Dim sValue As String
    Dim vValue As Variant

    lValue = 123456
    cValue = 1234.56
    nValue = 1234.56
    dValue = 1234.56
    sValue = "1234.56"
    vValue = CDec(1234.56)

    Open "c:\test1.bin" For Binary As 1
    Open "c:\test2.bin" For Binary As 2
    Open "c:\test3.bin" For Binary As 3
    Open "c:\test4.bin" For Binary As 4
    Open "c:\test5.bin" For Binary As 5
    Open "c:\test6.bin" For Binary As 6

    Put #1, , lValue
    Put #2, , cValue
    Put #3, , nValue
    Put #4, , dValue
    Put #5, , sValue
    Put #6, , vValue

    Close #1
    Close #2
    Close #3
    Close #4
    Close #5
    Close #6
End Sub

You can then inspect each file in a hex editor (I use MadEdit but anything will do).

It's probably useful to also try simple values like 1.00, 2.00, 10.00, -1.00 and see how the bytes differ each time.

This may also be informative (fairly in depth):

http://www.codeguru.com/vb/gen/vb_misc/algorithms/article.php/c7495/How-Visual-Basic-6-Stores-Data.htm

And to actually answer the question, something like the following will read a 32 bit integer and convert to currency:

Function ReadAmount(iFileHandle As Integer, lFileBytePosition As Long) As Currency
    Dim lValue As Long

    Seek #iFileHandle, lFileBytePosition
    Get #iFileHandle, , lValue

    ReadAmount = CCur(lValue) / 100
End Function

There's no need for an intermediate byte array.

Upvotes: 1

Proger_Cbsk
Proger_Cbsk

Reputation: 462

True floating point are bad when using currency, so actually your number is an integer with fixed point. First : put them in an integer variable (type Long) Second : divide by 100 to get back the decimal !

Straightforward method to convert it to single:

Dim S(4) As Byte 'your 4 bytes, like (1)=&H40, (2)=&HE2 (3)=&H01, (4)=&H00

Dim Buffer As Long
Buffer = S(4) * 16777116 Or S(3) * 65536 Or S(2) * 256 Or S(1)
Dim flt As Single
flt = Buffer / 100

Upvotes: 0

Related Questions