none
How to read existing VB6 random access files with VB.net

    Question

  • I have 15 years’ worth of files (approx. 10,000) that were created using VB6 structures and stored using the random access method.  I am trying to write a conversion routine that will read the old structures and put them into a new format that is more compatible with the .net environment.  I have not been able to successfully read any of the old files using the tools available in .net.  Each file starts with a header record structure. The header record tells me how many tags are in the file.  The next record (ie record number 2) is the first tag pointer record in the file.  There are num_of_tags of the pointer records.   Each pointer record has the string that holds the tag's ’literal name and two long integers that tell where in the file this tags records are.  Those actual records are stored as History data structures,

    The header record has the form:

       Type Head_record1

            num_of_tags As integer

            record_dt As variant

            Type As integer

        End Type

     

    The header is followed by tag structure that has pointers to the actual records for each tag:

     

        Type tag_Struct

            Tag_id As String * 20

            Start_rec As Long

            Last_rec As Long

        End Type

     

    Each tag’s data is stored in records that have the following structure:

     

        Type History_Data

            TimeStamp As Variant

            value As Single

            quality As String * 8

        End Type

     

    The files all have the same record length of 28

    I have tried reading the data into an object and casting the object into a structure that looks like the old type but that fails.  I have tried to read the file as binary streams getting one variable at a time but invariably lose track of where it is and start getting junk.

    I do not have any problem with creating new structures in VB.net and reading and writing them to file.  My problem is reading the old file so that I can convert them in to the new .net structures.

    I have tried using:

        Structure Head_record1

            Dim num_of_tags As Short

            Dim record_dt As Object

            Dim Type As Short

        End Structure

     

        Structure New_His_tag_Struct

            <VBFixedString(20)> Dim Tag_id As String

            Dim Start_rec As Long

            Dim Last_rec As Long

        End Structure

     

        Structure New_History_Data

            Dim TimeStamp As object

            Dim value As Single

            <VBFixedString(8)> Dim quality As String

        End Structure

     

    With FileGet, FileGetObject, and opening the file for random and binary.  I have also tried using a BinaryReader without any success.

     

     

    Can anyone come up with a solution that does not involve writing a VB6 DLL to read these files?

    Thank you in advance!


    E. L. Cranford
    Saturday, October 30, 2010 7:16 PM

Answers

All replies

  • This is not a VB6 forum.

    Renee

    Saturday, October 30, 2010 8:50 PM
  • Post your BinaryReader code.  It's the method that gives the most control.  Option Strict Off allows late binding, which may help, but it's sloppy.
    Saturday, October 30, 2010 8:51 PM
  • OP's question is how to read files which were created in VB6 using VB.Net.   The answer??   Probably need to track down the details of how VB6 structures UDT's in random access files, read them as Byte Arrays and then slice and dice on the right offsets.  OTOH, if still have access to VB6 build a simple function and do a batch conversion to XML or some other format.  Seems like a one time only  adventure.


    David Marso/TrancePlant
    Saturday, October 30, 2010 9:09 PM
  • Whenever I have done this I have not tried to map the old structure to the new one - it seems to get too complex very qiuckly.

    The alternative is to read the file as a byte stream and then write code to divide the resulting array into the data elements one by one. Part of the reason for doing this is that I usually have to write this code in order to examine the input file at the byte level to confirm that it really has the structure that I think it has!.  And cnce I've done that, converting the byte array into the required variables is easy.  An example is your timestamp object - do you have the details of the size and format of this object, and what process is required to convet it to a .Net date time object?

    Saturday, October 30, 2010 11:00 PM
  • Hi turtlebase,

    Please see this thread for an example on RANDOM ACCESS files.>>

    http://social.msdn.microsoft.com/Forums/en/vbgeneral/thread/50d7b930-edd3-4ba4-92fe-2c16e5235e51

     

    Regards,

    John



    Regards,

    John

    www.johnaoliver.com
    Sunday, October 31, 2010 12:45 AM
  • Thanx to all answers

     

    as for Johns approach i have implimeted this wouthout sucess when it comes to reading the actual data records:

    Private

     

     

    Sub ReadOldFileTagnames(ByVal sFile As String, ByRef TagNames() As String, ByRef bError As Boolean)

     

     

    Dim FileNumber As Integer

    FileNumber = FreeFile()

     

     

    Dim Head_record As New Head_record1

     

     

    Dim recordLength As Integer = 28 'Len(Head_record)

     

     

    Try

    bError =

     

    False

    FileOpen(FileNumber, sFile,

     

    OpenMode.Random, OpenAccess.Read, OpenShare.Shared, recordLength)

    FileGet(FileNumber, Head_record, 1)

     

     

    Dim myOldTag As New Old_His_tag_Struct

     

     

    Dim myNewTag As New New_His_tag_Struct

     

     

    ReDim TagNames(Head_record.num_of_tags - 1)

     

     

    For i = 1 To Head_record.num_of_tags

     

     

    If Head_record.Type = 0 Then

    FileGet(FileNumber, myOldTag, i + 1)

    TagNames(i - 1) = myOldTag.Tag_id

     

     

    Else

    FileGet(FileNumber, myNewTag, i + 1)

    TagNames(i - 1) = myNewTag.Tag_id

     

     

    End If

     

     

    Next

     

     

    'Close the file.

    FileClose(FileNumber)

     

     

    Catch ex As Exception

    bError =

     

    True

     

     

    End Try

     

     

    End Sub

    This works up unitl it hits the data loop, any clues?

    The original data struture was:

    Type History_Data
        TimeStamp As Variant
        value As Single
        quality As String * 8
    End Type

    The VB.net structure I used was:

    Structure

     

     

    New_History_Data

     

     

    Dim TimeStamp As Object

     

     

    Dim value As Single

    <

     

    VBFixedString(8)> Dim quality As String

     

     

    End Structure

     


    E. L. Cranford
    Sunday, October 31, 2010 2:39 PM
  • You'll be way ahead using Acamar's advice.  Learning to use the legacy methods is basically wasted learning.  Learning to use the BinaryReader and BinaryWriter will apply throughout your .NET code when working with streams.  It will be particularly usefull for WinAPI interaction.
    Sunday, October 31, 2010 3:02 PM
  • Create a binary reader and use it to access the file.
    http://msdn.microsoft.com/en-us/library/2k01zeat.aspx

    Use the Position method of the BaseStream member to seek to any byte position in the file.  In your case it will be calculated from the record number and the record length (remembering that the byte position starts at zero).

    Use the ReadBytes method of the binary reader to read the file data into an array of bytes.  Use the record size to control the reading.
    http://msdn.microsoft.com/en-us/library/system.io.binaryreader.readbytes.aspx

    Now use the appropriate conversion method from the BitConverter class to create each variable from selected portions of the byte array.  Eg:
    http://msdn.microsoft.com/en-us/library/system.bitconverter.toint32.aspx

     

     

    Sunday, October 31, 2010 9:45 PM
  • Hi Acamar,

    I'm good with everything you have except use of the BitConverter class.  I'm not sure about converting the variant.  Sometimes the data was stored as a Date Timestamp and sometimes as a number.  I guess that I could always use a double. Am I correct in assuming that I would always provide the BitConverter with the full record and adjust only the starting position for each field conversion of that record?

    Thank you

     


    E. L. Cranford
    Monday, November 08, 2010 2:51 PM
  • I'm good with everything you have except use of the BitConverter class.  I'm not sure about converting the variant.  Sometimes the data was stored as a Date Timestamp and sometimes as a number.  I guess that I could always use a double.

    I thought the timestamp might create a problem.   It might be a number (eg, Long) in all cases, simply needing a conversion to a date time, such as counting the seconds from 01/01/1970. That would be relatively simple, as you could use the result of that calculation to determine whether or not it is really a date.  Otherwise you need to be able to determine whether it's a timestamp or a number (based on some other part of the recrod?) and apply the appropriate conversion, and then you would need to dissect the bit structure of the timestamp to work out how to convert it into a date.   For instance it might be a DOS file date/time, which uses bit sequences of different lengths. Or, it might be a double where the whole part indicates the date and the fractional part the time. If you can't determine the exact format from the original code, then the only option is to examine the data at the byte and bit level, and experiment.  

    Am I correct in assuming that I would always provide the BitConverter with the full record and adjust only the starting position for each field conversion of that record?E. L. Cranford

    Including the start position of the required bytes within a longer byte array is a convenience provided in several of the overloads of the bitconverter methods, but in practice there's no particular advantage in doing it one way or the other.  My conversions are usually hard coded, so my personal preference is to dissect the record byte array into separate field byte arrays.  But if you are driving the conversion from a table that defines the conversion type and start position for each field within the record (which is a powerful technique when you have different format records in the file)  then the ability to pass the start position of the current field to the bitconverter could be useful.  Just choose what seems simplest. 
     

    Monday, November 08, 2010 9:46 PM