Library tutorials & articles

Binary Files

Practical Uses

Now that we have covered the basics of binary access, we can move on to its main uses. One of the great things about binary access is not only that we can store strings and numbers, but arrays, UDTs (User-Defined Types), and variants too. This is immensly useful if we need to store an array of UDTs, which, for example contained a collection of items which stored a name, keywords, an authorid and url. For example, imagine we had the following UDT:

Private Type Resources
    Name As String
    Keywords As String
    AuthorID As Long
    URL As String
End Type

and had an array containing a number of these items...

Private cResources() As Resources

Using binary access, it is easy to save, and restore the items in this array to a file. Along with this, we could also store data such as the category that all these items applied to, and a unique id of the application that saved it (this serves as a useful check that the file we are opening is in the format we expect it to be in). These two bits of data could be stored in the following variables:

Private sCategory As String
Private sAppIdent As String * 5
Private nAppVersion As Integer

Note that in this case we use * 5 after the variable sAppIdent to specify that this string is always going to be 5 characters in length.

Now lets take a look at the code we are going to need to save it. First, in the Form_Load procedure, we need to set the other information for sCategory and sAppIdent, and then create a FillData procedure to fill the array with some dummy items:

Private Sub Form_Load()
    sAppIdent = "DVPAD"
    nAppVersion = App.Major
End Sub
Private Sub FillData()
    ReDim cResources (1 To 2)
    With cResources(1)
         .Name = "Example 1"
         .Keywords = "winsock, ftp"
         .AuthorID = 1
         .URL = "http://vbweb.co.uk/"
    End With
    With cResources(2)
         .Name = "Example 2"
         .Keywords = "webbrowser, ie "
         .AuthorID = 3
         .URL = "http://codehound.com/"
    End With
    
    sCategory = "Internet"
End Sub

Next, we can create a procedure to save this data to disk:

Private Sub SaveData()
Dim nFileNum As Integer
Dim nLen As Integer, i As Long, lCount As Long
On Error Resume Next

'delete any existing file
Kill App.Path & "example.bin"
On Error Goto 0
nFileNum = FreeFile
Open App.Path & "example.bin" For Binary Access _
   Write Lock Read Write As #nFileNum
'output app id
Put #nFileNum, , sAppIdent
'output major version
Put #nFileNum, , nAppVersion

'get the length of the category
nLen = Len(sCategory)
'output them both...
Put #nFileNum, , nLen
Put #nFileNum, , sCategory
'save the number of items in array
lCount = UBound(cResources)
Put #nFileNum, , lCount
'save the array
For i = 1 To lCount
    Put #nFileNum, , cResources(i)
Next i
Close #nFileNum
End Sub

and then some code to read all the data back again...

Private Sub ReadData()
Dim nFileNum As Integer, lCount As Long
Dim sFileAppIdent As String * 5, nFileAppVersion As Integer
Dim nLen As Integer, i As Long
nFileNum = FreeFile
Open App.Path & "example.bin" For Binary Access _
   Read Lock Read Write As #nFileNum
'read app id.. we don't need to
'initialize string because we declared it As String * 5
'so it is always 5 chars
Get #nFileNum, , sFileAppIdent
'verify that this is correct, if not
'we are reading an invalid file
If sFileAppIdent = sAppIdent Then
    'check major version
    Get #nFileNum, ,
nFileAppVersion
    If nFileAppVersion < nAppVersion Then
        'we may need to use an function to convert
        'to a newer format...
    ElseIf nFileAppVersion > nAppVersion Then
        'produced by a later version...
        'we might have trouble reading it
    End If
    'get the length of the category
    Get #nFileNum, , nLen
    sCategory = Space$(nLen)
    'get category
    Get #nFileNum, , sCategory
    'get num of items in array
    Get #nFileNum, , lCount
    If lCount > 0 Then
        'resize array
        ReDim cResources(1 To lCount)
        'read items into array
        For i = 1 To lCount
            Get #nFileNum, , cResources(i)
        Next i
    End If
Else
    Msgbox "Invalid File"
End If
'that's it!
Close #nFileNum
'stop, so we can take a look in the Locals window
Stop
End Sub

Now, add 3 buttons to your form, and make each one call one of the procedures. Next, run your project, click the button which calls FillData. This fills the array with dummy items. Next, click the button which calls SaveData. This saves the items in the array to a file. Now, close your application. Start it up again, and this time click the button which calls LoadData. This will have filled the array using the data in the file, and paused VB at the Stop statement. Finally, click View|Locals. If you expand the object 'Me', and then 'cResources', you will be able to see the items re-loaded into the array.

Now you can create your own file formats to save your application data to a binary file....

Comments

  1. 21 Jun 2007 at 14:43

    it helps me a lot, thanksBig Smile [:D]

  2. 28 Jun 2006 at 10:57

    Thanks it was very helpfull

  3. 01 May 2006 at 07:34

    I want to read a binary file whitch saved by a Grid Option.how Can i Read this file and retrieve data from file. 

  4. 12 May 2004 at 08:03

    I am struggling for long time to display a GIF file on an ASP page. I have tried to return a GIF file in  few formats
    from a webservice.
    Webservice returns the images as MemoryStream.GetBuffer(). Its an array of unsigned bytes.I also tried to return it
    in base64 encoded format.


    I can call this webservice in either of 2 ways


    1) Directly from ASP -- It returns me this ..


    ÿØÿàJFIF`ÿÛC    $.' ",#(7),01444'9=82&lt;.342ÿÛC  2!!22222222222222222222222222222222222222222222222222ÿÀ(("ÿÄ ÿĵ}!1A <br> Qa"q2‘¡#B±ÁRÑð$3br‚ %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyzƒ„…†‡ˆ‰Š’“”•–—˜™š¢£¤¥¦§¨©ª²³´µ¶·¸¹ºÂÃÄÅÆÇÈÉÊÒÓÔÕÖרÙÚáâãäåæçèéêñòóôõö÷øùúÿÄ ÿĵw!1 <br> AQaq"2B‘¡±Á #3RðbrÑ $4á%ñ&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz‚ƒ„…†‡ˆ‰Š’“”•–—˜™š¢£¤¥¦§¨©ª²³´µ¶·¸¹ºÂÃÄÅÆÇÈÉÊÒÓÔÕÖרÙÚâãäåæçèéêòóôõö÷øùúÿÚ ?ôp2zW'©øîÒËR‚ XVæ}¢BNçùzž‹SÓ›WÒ <br> ®4ô»kG›d)Çð·}§úÃÇ/¬.tÛÉ-nâhæCÈ=Çb=Aõ®zÓ”v=l· FµÜÝßoÔõ‹ïh¶)½äÒ€ÐÃlf-ýÜŽÜœöãšsø–úÍÍ÷†/­ìˆ½ œp99Qøf¹Ï‡ú…•½ôösÀ¿j¹[ÍŒ{§¶G§qŽõéò¬[&lt;Ő„hó '•&gt;Æœ¦¯r1èágìÜ/æßåbµ­ÌW–Ý@áá™w#Û§&gt;‡Ž”Vƒv¦ª[#“ <br> µû, Oðsÿ ¯çEk sFç"’¥UÁlŽ’$JˆI˜@Î?õÄÇ£Çã+ÍsT™Þ8’e¶´ çã#¾Gç]´D ³m†O¥s> ;4ÛÍ4¡v—R4ÉŽ@ ãÓJ‰¤ä“:0³•:UCuoÌó½KK¾ÐuouE2Èã£̧¸¯R±ñ#Iá3â ”òf‰



    2) From VB(again I am returning byte array) which inturn is called by ASP -- I get the
    same junk as above.


    I need to convert it as a GIF file in my ASP page.
    Can you guys suggest how it could by achived. I am open to change code at any layer.


    Note - I am not getting any file back from VB or Web service. I am only getting it in some encoded format(byte array
    or base64)


    My ASP code is like this -


    <%@ LANGUAGE="VBSCRIPT"%>
    <% Response.Expires = 0
    Response.Buffer = True
    Response.clear
    Response.contenttype =  "image/gif"
    Response.AddHeader "content-disposition", "inline; filename=MyMap.gif"


    Set myEXE = CreateObject("ExFireSafeMapInfoTool.MapInfo")
    varGetImage = myEXE.GenerateMapForHousehold()
    RESPONSE.BinaryWrite (varGetImage)


    'Value of varGetImage -- Dont know what format is this?


    ÿØÿàJFIF`ÿÛC    $.' ",#(7),01444'9=82&lt;.342ÿÛC  2!!22222222222222222222222222222222222222222222222222ÿÀ(("ÿÄ ÿĵ}!1A <br> Qa"q2‘¡#B±ÁRÑð$3br‚ %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyzƒ„…†‡ˆ‰Š’“”•–—˜™š¢£¤¥¦§¨©ª²³´µ¶·¸¹ºÂÃÄÅÆÇÈÉÊÒÓÔÕÖרÙÚáâãäåæçèéêñòóôõö÷øùúÿÄ ÿĵw!1 <br> AQaq"2B‘¡±Á #3RðbrÑ $4á%ñ&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz‚ƒ„…†‡ˆ‰Š’“”•–—˜™š¢£¤¥¦§¨©ª²³´µ¶·¸¹ºÂÃÄÅÆÇÈÉÊÒÓÔÕÖרÙÚâãäåæçèéêòóôõö÷øùúÿÚ ?ôp2zW'©øîÒËR‚ XVæ}¢BNçùzž‹SÓ›WÒ <br> ®4ô»kG›d)Çð·}§úÃÇ/¬.tÛÉ-nâhæCÈ=Çb=Aõ®zÓ”v=l· FµÜÝßoÔõ‹ïh¶)½äÒ€ÐÃlf-ýÜŽÜœöãšsø–úÍÍ÷†/­ìˆ½ œp99Qøf¹Ï‡ú…•½ôösÀ¿j¹[ÍŒ{§¶G§qŽõéò¬[&lt;Ő„hó '•&gt;Æœ¦¯r1èágìÜ/æßåbµ­ÌW–Ý@áá™w#Û§&gt;‡Ž”Vƒv¦ª[#“ <br> µû, Oðsÿ ¯çEk sFç"’¥UÁlŽ’$JˆI˜@Î?õÄÇ£Çã+ÍsT™Þ8’e¶´ çã#¾Gç]´D ³m†O¥s> ;4ÛÍ4¡v—R4ÉŽ@ ãÓJ‰¤ä“:0³•:UCuoÌó½KK¾ÐuouE2Èã£̧¸¯R±ñ#Iá3â ”òf‰


    %>


    My VB Component function is something like this -


    Public Function GenerateMapForHousehold() As Variant


     Dim szFileName      As String
     Dim oSOAP           As New SoapClient30     'Soap Type Library 3
     Dim bytImage()      As Byte
     Dim szPicture       As String
     Dim iCount          As Integer
     Dim File            As Integer
     File = FreeFile
     
       'Make the Call to Web Service to retrive the Image.
       oSOAP.ClientProperty("ServerHTTPRequest") = True
       oSOAP.MSSoapInit "http://localhost/WebService1/GetImage.asmx?WSDL"
       bytImage = oSOAP.GetImage("bayshore.gif")
       GenerateMapForHousehold3A = bytImage
       
       'I can retreive this image in VB using this code -
       'szPicture = App.Path & "\Test.gif"
       'Open szPicture For Binary As File
       'For iCount = LBound(bytImage) To UBound(bytImage) - 1
       '  Put #1, , bytImage(iCount)
       'Next
       'Close #1
       'GenerateMapForHousehold = szPicture
       'Set Form1.imgTest.Picture = LoadPicture(GenerateMapForHousehold)


    End function



    And web service(c#) method is something like this-


    using System.IO;
    using System.Drawing.Imaging;
    public byte[] GetImage(string strFileName)
           {
               StreamWriter sr;
               Byte sIn = new Byte();
               Image MyImage;
               MemoryStream MemStr = new MemoryStream();
               MyImage = new Bitmap(Server.MapPath( strFileName));
               MyImage.Save(MemStr, ImageFormat.Jpeg);
               return  MemStr.GetBuffer();
           //I have 1 more function to return base64 encoded string but dont know how to use it further.


       }


    Please help.
    Thanks
    Mohit
    e mail - mohitFL@hotmail.com

  5. 03 Mar 2004 at 13:15
    Well I didn't notice the date in the upper left corner
  6. 02 Mar 2004 at 14:22
    Well this thread's ancient, I know that now. Heck, I think I knew back then too, but didn't bother typing it out.
  7. 02 Mar 2004 at 10:41
    Never use 1 as file number. Use
    Code:

    Dim FileNo As Integer
    FileNo = FreeFile
    Open ... ... As #FileNo
    Get #FileNo, , FileStr

    [courier new]// Mathias[/courier new]
  8. 02 Mar 2004 at 10:38

    Hi. I'm having a similar problem, I just can't get the header. I want to check if a .BMP file is in the right format. The header is BM, but i'm just getting M8 as header. That must be wrong . How do you get the header? Isn't it just

    Code:
    Get #FileNo, 2, sHeader
    ??

  9. 04 Nov 2003 at 13:34
    I am having a trouble reading binary data

    I have the following from the tutorial:

    Quote:

    Dim nFileNum As Integer, sString As String
    nFileNum = FreeFile
    Open "C:\Example\Example.txt" For Binary Access _
      Read Lock Read Write As #nFileNum
    sString = Space$(6)
    Get #nFileNum, 1, sString
    Close #nFileNum
    MsgBox sString
    [/Quote]

    It reads the value in the file fine, but since i wrote the file in binary it reads it back in binary and all i get is a ""

    Am i missing something... does the file need to be read in a certain way?
  10. 31 Aug 2003 at 22:19

    I don't know what I am doing wrong, but I would like to be able to read and write to *.exe and *.dll files. The problem is that it only gets the header ( MZ ). Does anyone know what I may have done wrong, or another method that can open EXE and DLL files? Thanks!


    -vivi0

  11. 30 Mar 2003 at 01:49

    How do I find the size of the file?
    [edit] Nevermind. LOF(1) seems to be it.

  12. 30 Mar 2003 at 01:43

    If everything you ever wanted to work with were an INI file, that'd be perfect. But if you want to make any sort of editor chances are you'll be using Binary file access.

  13. 26 Dec 2002 at 12:30

    Hi Shotgunner,
    I assumed that a binary file that could be read by C/C++ could also be read in VB.  There are constraints on how to do that but here goes.  In the code I posted before I created a binary file.  Here's the code I used to read it and write out the equivalent integer (or more correctly long) data in VB:
    Private Sub cmdRead_Click()
       Dim ibyte(2) As String * 1
       Dim tot, temp As Long
       Dim ind As Integer
       For ind = 0 To 19
           Get #1, , ibyte(1)
           Get #1, , ibyte(2)
           temp = Asc(ibyte(2)) * 2 ^ 8
           tot = Asc(ibyte(1)) + temp
           txtData(ind * 3).Text = tot
           txtData((ind * 3) + 1).Text = Asc(ibyte(1))
           txtData((ind * 3) + 2).Text = Asc(ibyte(2))
       Next ind
    End Sub


    Private Sub mnuExitProgram_Click()
       Unload frmBin
    End Sub


    Private Sub mnuFileOpen_Click()
       Open "test.dat" For Binary As #1
       cmdRead.Enabled = True
    End Sub


    Obviously I won't be sending you the forms.
    Here's the C (or more correctly the VC++ ) code that accomplishes a similar purpose:


    include <fstream.h>


    include <iomanip.h>


    int main()
    {
       unsigned ind, tot;
       unsigned char byte[2];
       ifstream infile("test.dat", ios::in );


       for ( ind = 1; ind <= 20; ind++ )
       {
           infile.read( byte, 2 );
           tot = byte[0] + ( byte[1] << 8 );
           cout << setw(8) << ind << setw(8) << tot << setw(8) << (int)byte[0] << setw(8) << (int)byte[1] << endl;
       }
       return 0;
    }


    Both programs read in the binary data from test.dat and displayed (either to console or to form) the equivalent numerical data.

  14. 20 Dec 2002 at 17:55
    thanx
  15. 20 Dec 2002 at 08:35
    Quote:
    [1]Posted by TheShotGunnner on 24 Nov 2002 09:16 PM[/1]
    Is it possible to read a C++ written binary file into visual basic and write it again using vb then have it read by c++. If it is then can someone please tell me. also how do you write a typefef structure into a file using c++. Does anyone know. I would really appreciate it.


    A binary file is a binary file regardless of which language creates it.  The following code reads in a binary file 2 bytes at a time (the read statement) and then writes them to another binary file 2 bytes at a time (the write statement)
    #include <fstream.h>
    #include <iomanip.h>
    int main()
    {
       int ind, tot;
       unsigned char byte[2];
       ifstream infile("2000_09_28_18_40_11_Sen2_Grp0.dat", ios::in );
       ofstream outfile("test.dat", ios::binary );

       for ( ind = 1; ind <= 20; ind++ )
       {
           infile.read( byte, 2 );
           outfile.write( byte, 2 );
           tot = byte[0] + ( byte[1] << 8 );
           cout << setw(8) << ind << setw(8) << tot << setw(8) << (int)byte[0] << setw(8) << (int)byte[1] << endl;
       }
       return 0;
    }

    I plan to test test.dat later and make sure that VB can read it.  But I have little doubt that it will.  You may wonder what I was writing to the screen with cout.  (This is important to consider.)    Often binary files contain 2 byte integers split into two separate bytes.  Here I was taking the bytes and recombining them into their original value. For example the first two number that are read are 208(byte[0] ) and 7 (byte[1]).  Shifting the the 1 byte 7 8 places (the equivalent of multiplying by 256) and then adding it to byte[0] to make an integer 2 bytes long equals 2000.  7 * 256 + 208 = 1792 + 208 = 2000 or looked at another way 00000111 010110000 is a 16 bit representation of 2000.

    I hope this helps.

    David
  16. 24 Nov 2002 at 21:16
    Is it possible to read a C++ written binary file into visual basic and write it again using vb then have it read by c++. If it is then can someone please tell me. also how do you write a typefef structure into a file using c++. Does anyone know. I would really appreciate it.
  17. 01 Nov 2002 at 23:09

    And don't forget, data files shouldn't be written to the registry.

  18. 11 Dec 2001 at 14:03

    The Len() function returns null if the file is open in binary mode. Use the LOF() function instead.


    Another thing, String() function is better to use than Space() function because if you have used value bigger than new value, Space() only fills string with spaces, leaving the size as is, but String() resizes the strng.

  19. 24 Oct 2001 at 06:40

    This is a 2 ways method, if your program very much independent on settings inside the INI files you just have to read and write the INI files at all times.


    Or if ur program is mostly put the value inside the registry for a one-time settings of something in conjunction to the system setting, registry would be better.


    But i prefer using INI files since it can be separated from the syste, registry and avoid corruption.


    One more thing is in registry, you can organize ur setting in parent and child relationship but not INI file.

  20. 23 Oct 2001 at 23:28

    Since you can do the same kind of stuff like this and save it to the registry, which is easier, why use binary files?  I could see it if you had a LOT of values, but then wouldn't you just use and INI file or something for conveienience?  I guess keeping things secret, like passwords, you might use a bin file for, but what could it be used for other than that?

  21. 01 Jan 1999 at 00:00

    This thread is for discussions of Binary Files.

Leave a comment

Sign in or Join us (it's free).

James Crowley James first started this website when learning Visual Basic back in 1999 whilst studying his GCSEs. The site grew steadily over the years while being run as a hobby - to a regular monthly audience ...
AddThis

Related discussion

Related podcasts

  • Christian Beauclair

    14 mai 2008 (�mission #0074) ::.Christian Beauclair: Stratégies de migration VB6 vers .NET Nous discutons avec Christian Beauclair des stratégies de migration VB6 vers .NET. Entre autres, nous discutons comment utiliser le "VB 6 Code Advisor" et le "Interop Forms Toolkit" pour ajouter la puiss...

Want to stay in touch with what's going on? Follow us on twitter!