Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations Westi on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Read a binary file using VB 2

Status
Not open for further replies.

cyberbiker

Programmer
Mar 16, 2001
431
US
This is a bit of a general description. The code involved in the
whole situation is quite extensive. I can provide more information
if necessary, but I suspect I am overlooking some basic premise
in reading a binary file
I am trying to read a binary file with Visual Basic.
This binary file is a parameter file from a program written in PASCAL.
First the program will read an ASCII text "driver file". From that
I determine the the parameter in the binary file along with
other information I need to process, create an appropriate control "on
the fly" and place all the information in a user defined type.
At this point I determine the length of the field from the data type
of the parameter as declared in the "driver file".
I keep a counter and add the length of the field to the counter each time
determine the offset of the next record starting at "1" instead of "0"
example:

header field is always 8 bytes therefore the start position of the
first needed field is always 9
length of first applicable record = 2 bytes
offset for second field then will be 11

I then read this array, placing the control on the proper tab and
frame.
Things work perfectly up to this point
I then read the binary file using "Get" It seems to work fine
through the first 12 parameters no matter what data type. Then,
after that, it breaks down, somehow. Obviously I am breaking down
in the offset but why?
Terry (cyberbiker)
 
What do you mean "it breaks down, somehow"? As you undoubtedly know, reading information in binary requires you to declare a fixed length string to recieve the data. Is it possible that your fixed length string is being sized based on the size of the data type(i.e. Long = 4 bytes) instead of the number of bytes to read (i.e. 14359 = 5 bytes)? Need more info, methinks!

-Mike Difference between a madman and a genius:
A madman uses his genius destructively,
A genius uses his madness constructively.
 
When I said it "breaks down" I mean I start getting some very strange data. It is as if I am starting to read a field "early" or "late" ie: offset should be 139 and I am actually tying to start at 138 or something along those lines.
The fixed length string IS being sized based on the data type.
This is per instructions from a senior programmer here who wrote the PASCAL based program that I am trying to integrate into VB.
additionally there are variable length strings. The driver file indicates the max length, the first byte indicates the actual length of the string and the total bytes in the field are max length + 1 I use the following function to handle those strings.

Function GetPascalString(ByVal f As Integer, ByVal maxlen As Long) As String
'--- Reads a pascal string from file <f> of up to <maxlen> characters
Dim plen As Byte, pchar As Byte
Dim txt As String

txt = &quot;&quot; ' String stored here
Get #f, ControlInfo(RefDigi).goffs, plen ' Read actual string length starting at control
'offset
Dim ix& 'as long
For ix = 1 To plen 'from 1 to actual length
Get #f, , pchar 'Read string character and add to string

txt = txt & ChrW(pchar) 'convert to unicode byte to string
Next ix 'loop
'--- Skip unused characters
For ix = ix To maxlen 'read to max length
Get #f, , pchar 'read string character and discard
Next ix 'loop
GetPascalString = txt 'returns value
End Function


in my test data the 11th and 12th parameters are these &quot;Pascal Strings&quot;. Since they are one of the few parameters I know the data that is supposed be in this file
I have been able to determine that I am reading to this point correctly

other data types are handled differently. for example an &quot;array of bytes&quot; will have a length defined in the driver file.

I determine the offset (or starting position for each field) by adding the actual length of all preceeding fields to the starting offset.

basing the fixed size string on the data type ie: long = 4 bytes works (or seems to) past this point.

I do not know if this clarifies anything. I have programmed for 2 years, but only a few months using VB. This program I am trying to finish is a nightmare and I am in a bit of an awkward situation here (older, working for an intelligent younger and somewhat poor communicating senior programmer)I am not totally certain how this binary file is actually laid out.
The following is the information I was given when I questioned:

> How do I get offset from PAT files? or????

The PAT file declares the parameters in the PAR file in the exact
order in which they appear in the PAR file. This allows you to
reconstruct the offset for a parameter in the PAR file when you
know the size of all the preceding parameters. You do from the
parameter type number:
Type #0: array of bytes. Not edited. 3rd number gives size
Type #1: boolean. 1 byte
Type #2: character, 1 byte
Type #3: 16-bit integer, 2 bytes
Type #4: double, 8 bytes
Type #5: Pascal string, 3rd number gives max string length.
Total length in PAR file is max string length + 1. Read this
string by reading 1 byte for the actual string length, then
this length times a byte for each character in the string.
Type #6: enum, 1 byte
Type #7: character array, 3rd number gives array length
Type #8: double, 8 bytes (display in LCD)
Type #9: array of records, 3rd number gives number of records
in the array, 4th number gives number of members in the record.
This definition is then followed by declarations for each member
in the record. The total byte size in the PAR file is the sum of the
sizes of each record member times the number of records in the
array.
Type #10: set, 3rd number gives set size. The size in the PAR
file is (set size + 7) / 8.
Type #11: hope it doesn't appear in any PAT file
Type #12: scaled integer (* 32), 2 bytes
Type #13: scaled long (*1000), 4 bytes
Type #14: integer, 2 bytes, edit as hexadecimal
Type #15: Motorola integer, 2 bytes
Type #16: Motorola integer, 2 bytes, edit as hexadecimal
Type #17: long, 4 bytes, edit as hexadecimal
Type #18: long, 4 bytes

Using the PAT file you sent:
#1: array of 7 bytes, offset = 0
#2: double, offset = 0 + 7 = 7
#3: double, offset = 7 + 8 = 15
#4: integer, offset = 15 + 8 = 23
#5: integer, offset = 23 + 2 = 25
#6: integer, offset = 25 + 2 = 27
etc...

I do appreciate your taking the time to read this. Any help would be appreciated.
Sometimes I do not have quite the ability to explain things, but often I just turn out to need one &quot;piece&quot; of knowlege to put it all together so feel free to make any suggestions at all (short of run screammng to the hills)
:)
Terry (cyberbiker)
 
For ix = 1 To plen 'from 1 to actual length
Get #f, , pchar 'Read string character and add to
...

It looks like you might want to replace the Get line with this:

Get #f, ix, pchar

Since pchar is a byte, you're only reading one character at a time (which means that you and the other programmer are right, the string length IS the same size as the data type). Incrementing the file pointer (ix) will ensure you're reading each sequential digit in the file (although this is supposed to be automatic, it's a good habit to have). That could possibly be where your &quot;breakdown&quot; is at.

Another thing I noticed is &quot;pchar&quot; is declared but not initialized. It may not help, but I think it would be a good idea to add the statement: pchar = Space$(1) before you use it. That may give VB a better way to increment the file pointer after each read.

Since you're reading data &quot;early&quot; or &quot;late&quot; in the file, the most likely reason is that file pointer in the Get statement. Watch it run closely with the debugger (especially toward the end of the operation), and keep track of where that pointer is.

Once you get this routine working, you may notice that it's really slow when reading large amounts of data in the same run. If that becomes the case, it's because reading one byte at a time is 10 times slower than reading it all at once and then processing the data. I recommend using that pchar = Space$(Number) statement to read everything in one operation, and then process the info in pchar as necessary.

Difference between a madman and a genius:
A madman uses his genius destructively,
A genius uses his madness constructively.
 
I appreciate the help and will work on this some more.
I think you have put me on track. I will let everyone know what happens.
Terry (cyberbiker)
 
Another note on your looping that could also be causing the 'drifting' you are experiencing..

You are using the same 'loop number' twice in your loops. To explain.. Here's your loops.


For ix = 1 To plen 'from 1 to actual length
Get #f, , pchar 'Read string character..
txt = txt & ChrW(pchar) 'convert to unicode byte to string
Next ix 'loop

'--- Skip unused characters
For ix = ix To maxlen 'read to max length
Get #f, , pchar 'read string character and discard
Next ix 'loop


Say for example plen starts in being 8 and your maxlen is 12. The first loop will count through working properly and end up with ix=8. The problem is when you get into the second loop and ix is still 8 looping up to 12 (maxlen). The loop is going to go through 5 times instead of the expected 4 and this may be where the drifting is occurring as you are reading an extra byte out of the file and throwing off the position. You can easily fix it by either changing the loop to read:

For ix = ix to maxlen - 1 '<--change
Get #f, , pchar
Next ix 'loop

or you could keep your original for loop and just increment ix by 1 before it gets to the second loop. IE.

ix = ix + 1
For ix = ix to maxlen
Get #f, , pchar
Next ix 'loop

Hope that this was understandable and helps. =)
 
after a decent nights sleep, I am looking at the world in a whole better light.
I realize that I am way off base in my search for the problem.
I have been looking at how I read the fields and really appreciate your help on this since it has taught me a valuable lesson.
But the issue is the start position of each field as I create the control.
Each control is created on the fly depending on what is needed.

offset = 9 'starting offset of parameter1

ControlInfo(intParamCount).goffs 'offset value for parameter

ControlInfo(RefDigi).glen 'length of field which is determined by data type using a case select statement.
if it is a &quot;Pascal String&quot; then the max length of the field is 1 + length defined in the &quot;driver file&quot; and the GETPascalString function would come into play when reading it.
regardless:

ControlInfo(RefDigi).goffs = offset
offset = ControlInfo(RefDigi).glen + offset 'increments offset by length of current field in bytes giving starting offset for the next field

I then read each field using Get(file, ControlInfo(RefDigi).goffs, variable name)

actually seems simple,but yet I am off. I am suspecting that I have some bad information in the *.PAT file which is an ASCII text file useded in the PASCAL program that I used to find the data types and length of each field.
The senior programmer is adamant that the *.PAT file is correct, but I have just found a way to test to see.

But what is currently happening is that the offset I start with somehow is not being incremented properly at some point in my code or the *.PAT file is goofy.
Anyway, appreciate all the information. I will digest it and I am certain it will help me later.


Terry (cyberbiker)
 
Just feed back for those who tried so hard to help me.
I am afraid my difficulty was caused by cranio rectal disease. Luckily that is not fatal, only embarrassing.
After questioning the senior programmer again, I found a PASCAL program that would print out the current values in the file I needed to read. After doing that, it became obvious I had made an error in writing the driver file and passed over a boolean value thus throwing everything off
Simple Terry (cyberbiker)
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top