Page 1 of 1

File Handling in Visual Basic 6 Part 2 - Binary File Handling Teaches Binary File Handling Methods of VB6 Rate Topic: -----

#1 born2c0de  Icon User is offline

  • printf("I'm a %XR",195936478);
  • member icon

Reputation: 180
  • View blog
  • Posts: 4,667
  • Joined: 26-November 04

Posted 29 June 2008 - 03:22 AM

FILE HANDLING USING VISUAL BASIC 6.0 PART II - BINARY FILE HANDLING



- Sanchit Karve
born2c0de
printf("I'm a %XR",195936478);


CONTACT ME : born2c0de AT dreamincode DOT net

CONTENTS
  • I. ASSUMPTIONS
  • II. BASIC RELATIONSHIPS
  • III. INTRODUCTION
  • IV. SEQUENTIAL FILES, BINARY MODE, BINARY FILES
  • V. BINARY FILE HANDLING
  • VI. READING AND WRITING IN BINARY MODE
  • VII. ACCESS-LOCKS
  • VIII. Hide and SEEK
  • IX. BINARY FILE HANDLING FUNCTIONS
  • X. BINARY FILE HANDLING EXAMPLES
  • XI. CONTACT ME



I. ASSUMPTIONS

The reader is expected to have read the first part of this tutorial which deals
with sequential files. You can still follow this tutorial without reading Part-I,
but I recommend reading the sequential files tutorial first because I may have mentioned certain things in Part-I which also apply to Binary Files.

II. BASIC RELATIONSHIPS

You might have heard several terms in File Handling such as Fields, Records etc.
but may not know what they mean.
To understand it simply remember this set of relationships:
8 Bits = 1 Byte/Character
Many Bytes/Characters = 1 Field (or String)
Many Fields = 1 Record
Many Records = 1 File
Many Files = 1 Database


III. INTRODUCTION

As far as Visual Basic 6 is concerned, there are three modes in which a file can
be accessed.
  • Text Mode (Sequential Mode)
  • Binary Mode
  • Random Access Mode
In the Text Mode, data is ALWAYS written and retrieved as CHARACTERS.
Hence, any number written in this mode will result in the ASCII Value of the
number being stored.
For Example, The Number 17 is stored as two separate characters "1" and "7".
Which means that 17 is stored as [ 49 55 ] and not as [ 17 ].

In the Binary Mode, everything is written and retrieved as a Number.
Hence, The Number 17 Will be stored as [ 17 ] in this mode and
characters will be represented by their ASCII Value as always.

One major difference between Text Files and Binary Files is that Text Files
support Sequential Reading and Writing. This means that we cannot read or write
from a particular point in a file. The only way of doing this is to read through
all the other entries until you reach the point where you want to 'actually'
start reading.

Binary Mode allows us to write and read anywhere in the file. For example we can
read data directly from the 56th Byte of the file, instead of reading all the
bytes one by one till we reach the 56th byte.

Part-I dealt with Sequential Files, and this one will teach you how to read and
write files in Binary Mode.

IV. SEQUENTIAL FILES, BINARY MODE, BINARY FILES

You will often come across the terms "Text Files", "Sequential Files",
"Sequential Mode", "Binary Mode" and "Binary Files" while reading books,
articles or even posts on the internet related to file handling and wonder what
they really mean.

A file is a set of bytes/records stored together.

Text Files are files which contain only characters in ASCII or Unicode.

Sequential Files are files opened in Sequential Mode.

Sequential Mode refers to any of the modes used for sequential file handling
which are Input, Output and Append.

Binary Mode refers to the Binary Mode [which you shall learn about as you
progress through this tutorial]

Binary Files refer to files opened in Binary Mode.

You should note that Binary Files and Sequential Files are not different kinds
of files but rather different methods of accessing a file.

Any file can be opened in both sequential and binary modes (obviously not at the
same time ;) ). If it is opened in sequential mode, you will only be able to
access data in the file sequentially. If it's opened in Binary mode, you can
access any byte in the file without reading the previous bytes in the file.

V. BINARY FILE HANDLING

Let us start with a very simple example:

'Add a Command Button with name as Command1 onto a Form
Private Sub Command1_Click()
   Dim f As Long
   f = FreeFile()

   Open "c:\test.txt" For Binary As #f
   Close #f
End Sub


As you can see, the FreeFile() function can also be used for binary files.
The Open Statement opens c:\test.txt in Binary Mode and the next statement
closes the file.

As obvious as it may sound, you need to open a file before using it and close it
when you have finished reading or writing to it. Many programmers forget to add
the Close statement which results in the File Already Open Error, and it can be
a pain to track down the exact location that caused the error when you're
dealing with many files.

You should note that this snippet does more than open and close a file.
If the test.txt file is not present in C drive, then it creates a blank file
with the same name.

VI. READING AND WRITING IN BINARY MODE

Now that you know how a file is opened, let us see how we can read and write
data in Binary mode.

Here's an example which writes a string in a Binary File.

'Create a Command Button as Command1
Private Sub Command1_Click()
    Dim f As Long
    f = FreeFile()
    Open "C:\abc.txt" For Binary As #f
    Put #f, , "This is the Test file."
    Close #f
End Sub


The string "This is the Test file." is written to the abc.txt file in the C
drive. The Put Statement is used to write data to a binary file. The Syntax of
Put is as follows:

Put #fileNumber, [startByte], varName


where
#fileNumber = A file handle ('f' is the file handle in the previous example)
startByte = (Optional) Byte position to start writing at.
varName = Variable/Literal whose contents are to be written. varName can be a variable of any data type.

In the above example, we have skipped the second parameter which means that the
string is written at the current position of the file, which in this case is the
beginning of the file. (More on this in Section VIII. Hide and SEEK)

We can choose to write data at a different position by specifying this parameter.
Change the Put Statement from the previous example to Put #f, 13, "B"

Now run the program, quit the program and open the abc.txt file. You will see
that the file now contains "This is the Best file."

The Put statement in this case writes "B" at the 13th byte in the file. You can
see that the 13th position in the file is the letter "T". Hence "T" gets
replaced by "B".

[ NOTE FOR ASSEMBLY, C AND EXPERIENCED VB6 PROGRAMMERS ]
Unlike other languages, VB6 does not store strings in ASCII format. The string
"ABCD" is stored in VB6 like this:
[ 00 08 65 00 66 00 67 00 68 00 ]
The first two bytes contain the length of the following string. The latter
portion of the string uses 2 bytes for every character. Hence the trailing zeros
for every character.

That's right, VB6 stores strings internally in Unicode but what I really want to
tell you is that while the length of this string is actually 10 bytes, when it
is written in a File VB6 ALWAYS STORES IT IN ASCII FORMAT.

For more information on how the VB6 Len() function works, click here to read my
blog post which elucidates the working of the function.



Now coming back to the topic. As you now know, the Put statement is used to
write to a binary file. The Put statement is also used to write to Random Access
Files. (More information on that in Part III of this tutorial)

A logical opposite of Put is Get, and that's what you'll need to use to read
data from a Binary File. Have a look at this fragment of code:

Private Sub Command1_Click()
    Dim f As Long
    Dim x As Byte

    f = FreeFile()
    Open "C:\abc.txt" For Binary As #f

    Get #f, , x
    Close #f

    MsgBox x
End Sub


This will display 84 (ASCII Value of T) in a Message Box. The syntax of the Get
Statement is exactly the same as that of the Put statement. Experiment with the
second parameter and notice how you get ASCII values of the other elements.

Let's try to read in the first word of the file. We know that the first word is
"This", so we'll create a Byte Array of length 4 like this:

Private Sub Command1_Click()
    Dim f As Long
    Dim x(3) As Byte 'Creates Array from Index 0 to 3
    Dim readresult As String

    f = FreeFile()
    Open "C:\abc.txt" For Binary As #f

    Get #f, , x
    Close #f
    readresult = Chr(x(0)) & Chr(x(1)) & Chr(x(2)) & Chr(x(3))
    MsgBox readresult
End Sub


Visual Basic will automatically fill in every element of the array x until it
can't store any more. So it starts from the first position (2nd parameter is not
specified) and copies the first 4 characters into the Byte Array x.

Since the array x is of data type Byte, we need to convert it to a string and
then display it as shown.

But can't we pass a string variable directly to the Get Statement?
Yes, you darn well can. Have a look:

Private Sub Command1_Click()
    Dim f As Long
    Dim readresult As String

    f = FreeFile()
    Open "C:\abc.txt" For Binary As #f

    Get #f, , readresult
    Close #f

    MsgBox readresult
End Sub


The output of this code is totally unexpected. It's null. The Message Box
doesn't display anything. Why is this so?

As I mentioned earlier, the Get statement automatically detects the length of
the string and fills up data into the variable till it can't store any more.

Ring any bells?

What's the length of the readresult string?

It's ZERO because nothing is stored in it initially, and hence nothing will be
stored in it after the Get statement.

To get the code to work as expected, we need to specify the length of the string
by either defining it as a fixed-length string or initializing it to a string of
non-zero length.

You can either define the string as a fixed-length string like this:
Dim readresult As String * 4


or initialize the string to something with its length as 4 like this:
Dim readresult As String
   readresult = String(4, " ") ' or even readresult = "ABCD"


Now, make the appropriate changes in the previous example and run the program.
The Message Box should display "This".

VII. ACCESS-LOCKS

An important point that deserves mention is that unlike sequential files, you
can read and write at the same time in Binary Mode. It is possible to read from
a file in one statement and write to it in the following statement but the same
cannot be done in sequential mode.

Since read and write operations are permitted on an open Binary file, there are
no further modes under Binary. (unlike sequential files which have Input, Append
and Output modes which permit only one operation)

But this isn't advantageous in every situation. Consider a situation where you
wish to ONLY read from a file. What if you write to the file by mistake? In
sequential mode, VB will flag an error saying you can't write in Input mode. But
since read and write operations are permitted in Binary mode, VB won't flag an
error and the file will get modified.

The same situation can occur when multiple users in a networked environment are
accessing the same file. It is quite possible for another user to modify data in
a file while you are reading it, which can lead to unexpected disastrous results.

Thankfully, Visual Basic gives you an option to set the permissions you need for
working on the file.

You can either specify these permissions when you open a file or Lock a
particular set of bytes after you open the file.

The supported Access Locks in VB6 are:
  • Shared : Other Users/Processes can Read and Write to the File even while your program is working on it.
  • Lock Read : No other program is allowed to read the file while you are working on it.
  • Lock Write : No other program is allowed to write to the file while you are working on it.
  • Lock Read Write : Other programs cannot read nor write to the file while you are working on it.
The above mentioned locks set permissions for other users and processes that try
to access the same file.

To set permissions for operations that you are allowed to do on the file, VB6
provides 3 access modes.
  • Read : You can only read the file.
  • Write : You can only write to the file.
  • Read Write : You can read and write to the file.

By using the access permissions and Lock modes, you can prevent your program
from being a victim to your own programming errors and multiple-user access
problems.

To use these permissions, you will need to specify them in the Open statement
like this:
Open <pathname> For Binary [Access] [lock] As #filenumber


where
pathname = Name of File
Access = Read / Write / Read Write
lock = Shared / Lock Read / Lock Write / Lock Read Write

Eg. To open the abc.txt file for read permission such that no other process can
use it while you are working on it your Open statement should look like this:

Open "c:\abc.txt" For Binary Read Shared Read Write As #1


These access permissions are applied on the entire file but you can also
selectively lock certain bytes in a file. The Lock statement enables you to do
this.

The syntax of Lock and Unlock are:

Lock [#]filenumber[, recordrange]

Unlock [#]filenumber[, recordrange]


where recordrange can have 3 types of values.
  • (Optional) i.e. No parameter passed as recordrange.
  • A Byte Position
  • x To y
In the first case if no parameter is specified, the entire file is locked or
unlocked.

If you specify 10 as a byte position (case 2), the file will be locked/unlocked
for all bytes starting from the 10th position.

If you specify 20 To 30 as the parameter (case 3), all bytes from 20 to 30 will
be locked/unlocked.

Examples:
Lock #1
Lock #1, 20
Lock #1, 20 To 40
Unlock #1
Unlock #1, 20
Unlock #1, 20 To 40


CAUTION:
You must use Lock and Unlock in pairs i.e. the arguments must match exactly.
Ensure that unlock every locked file before closing it or quitting your program.
Failure to do so produces unpredictable results.

IMPORTANT NOTE:
Locks and Access Permissions can also be set for Input, Output, Append and
Random Access Modes. However, specifying the byte range in Lock/Unlock for
sequential files still results in the entire file being locked. (It's called a
sequential file for a reason, you dummy!!! ;) )

VIII. Hide and SEEK

Consider a situation where you are interested only in bytes 100 to 110 and wish
to write certain bytes to these positions in a file. How would you go about
writing the Put statement?

Put #1, 100, <Byte1>
Put #1, 100, <Byte2>
...
Put #1, 109, <Byte9>
Put #1, 110, <Byte10>


or

For I = 0 to 10
    Put #1, (100 + i), <Byte_from_Array>
Next I


Yes, you could but there's a better way. VB6 provides a Seek() function and a
Seek statement which allows you to get/set the current position of an open file.

The Syntax of Seek is simple :
Seek #filenumber, BytePosition


You can now write the same code like this:

'Open the file with handle 1
Seek #1, 100
Put #1, , Byte1


The same works for the Get statement as well. You can use Seek() to set the
current position of the file for reading.

NOTE:
Unlike C and other languages which allow you to set different positions for
reading and writing, VB6 considers the same position for reading and writing.

If the second parameter is left blank in Get or Put, it will read/write from/to
the current position of the file specified by the last Seek() function executed.

Consider this snippet:
Seek #1, 100
Put #1, 200, "Hey"


In this case even though we have set the current position of the file to the
100th bit, the Put statement writes "Hey" from the 200th byte. If the second
parameter is specified, Get/Put ignore the position set by Seek().

Seek has another use. If you use Seek as a function, it will return the current
position of the file.
Hence,
Seek #1, 100
Msgbox Seek(1)


will display 100 in a Message Box.

The LOC() function also returns the current position in the file.

IX. BINARY FILE HANDLING FUNCTIONS

VB6 provides many more library functions which you can use for Binary File
Handling. Here's the list of functions that are related to Binary File Handling:
  • FreeFile():
    DESCRIPTION : Returns an Integer representing the nextfile number available
    for use by the Open statement.

    SYNTAX : FreeFile[(rangenumber)]
    The optional rangenumber argument is a Variant that specifies
    the range from which the next free file number is to be
    returned. Specify a 0 (default) to return a file number in the
    range 1 – 255, inclusive. Specify a 1 to return a file number
    in the range 256 – 511.

    USE : FreeFile() is used to avoid using a file handle that is already
    in use.

  • EOF():
    DESCRIPTION : Returns an Integer containing the Boolean value True when the
    end of a file has been reached.

    SYNTAX : EOF(filenumber)
    The required filenumber argument is an Integer containing any
    valid file number.

    USE : EOF() is occasionally used in loops to process a file until the
    End of File is reached.

  • FileLen() :
    DESCRIPTION : Returns a Long specifying the length of a file in bytes.

    SYNTAX : FileLen(pathname)
    The required pathname argument is a string expression that
    specifies a file.

    USE : FileLen() is Used to find the length of a file that has not
    been opened using the Open Command.

  • LOF() :
    DESCRIPTION : Returns a Long representing the size, in bytes, of a file
    opened using the Open statement.

    SYNTAX : LOF(filenumber)
    The required filenumber argument is an Integer containing a
    valid file number.

    USE : LOF() is used to find the length of a file when a file is
    currently open.

  • LOC() : *Thanks to Warren Brayshaw for correcting an error*
    DESCRIPTION : Returns a Long representing the read/write position in a file
    opened using the Open statement.

    SYNTAX : LOC(filenumber)
    The required filenumber argument is an Integer containing a
    valid file number.

    USE : LOC() is used to find the current position of the read/write
    pointer in the file.

  • Seek() :
    DESCRIPTION : Returns a Long specifying the current read/write position
    within a file opened using the Open statement.

    SYNTAX : Seek(filenumber)
    The required filenumber argument is an Integer containing a
    valid file number.

    USE : Seek() is used to get the Byte Position where the Next
    Operation will take place.
Along with the above mentioned functions, you can also use "B" character
functions such as AscB(), ChrB(), LeftB(), RightB(), MidB(), InstrB().

The only thing different about these "B" functions is that they work on Binary
Strings (hence the suffix 'B'). These functions have the same syntax as their
original non-B counterparts and is meant to be used in the exact same way.

X. BINARY FILE HANDLING EXAMPLES

Binary File Handling in any language is a very powerful tool in the hands of a
programmer. Use it with caution as even a tiny mistake has the potential to
destroy the entire file.

Binary File Handling is always used in situations where you either wish to
utilize space in the most efficient manner or if you wish to hide information
about the contents of the file or file format. (Microsoft Word files always use
Binary mode to hide the DOC format. Try opening a DOC file in Notepad)

Antivirus Programs also analyze files in Binary Mode. Virus Signatures are
basically a collection of unique bytes. The Antivirus application simply opens
the file in binary mode, seeks to the position of the virus signature (if known),
and searches for the presence of its set of Virus Signatures. A match means that
the file in question is infected with a Virus that has the same Virus Signature.

Although I could give simple code examples like those in Part-I of this tutorial,
I decided to show two very interesting examples using Binary File Handling.
Check them out and Have Fun with them.
  • Detect if a given File is an EXE File.

    Every valid EXE File has "MZ" as its first 2 bytes (known as Magic Number). We
    simply check if the first 2 bytes of a file have "MZ". Rename a file of another
    extension to EXE and test it with the code below.

    Private Function IsValidEXE(ByVal path As String) As Boolean
       On Error Resume Next 'If File Path is invalid
       Dim ret As Boolean
       Dim f As Long
       Dim magic As String * 2
    
       ret = False
       f = FreeFile()
    
       Open path For Binary As #f
       Get #f, , magic
       Close #f
    
       If magic = "MZ" Then ret = True
    
       IsValidEXE = ret
    End Function
    



  • Protect your executable file from being opened by unauthorized users.

    This is a simple trick. All we have to do is change the Magic Number "MZ" of the
    EXE file and change it to something else. Any attempt to run the modified
    executable file will fail. Windows will refuse to run invalid EXE Files.
    To 'unprotect' the file, we simply change it back to "MZ".

    Private Sub ProtectEXE(ByVal path As String)
      Dim f as Long
    
      f = FreeFile()
    
      Open path For Binary As #f
      Put #f, , "SK"
      Close #f
    End Sub
    
    Private Sub UnProtectEXE(ByVal path As String)
      Dim f as Long
    
      f = FreeFile()
    
      Open path For Binary As #f
      Put #f, , "MZ"
      Close #f
    End Sub
    


    CAUTION:
    Please Backup the appropriate file before passing its path to these functions.
    These functions do not damage the file, but it's better to play safe.
XI. CONTACT ME

This concludes the second part of a trilogy of VB6 File Handling Tutorials
written by me. As of this writing, I haven't yet submitted the third and final
tutorial on Random Access Files. I shall write and submit it very soon.

Keep checking the Tutorials Section for updates on the next tutorial.

If you find any errors in the tutorial contact me at born2c0de AT dreamincode DOT net and I'll make the changes immediately.

If you have any questions regarding this tutorial, please add a comment or reply
to this post or post your question on www.dreamincode.net , a programming and
web development community with over 94,000 members to get a prompt answer.
am a Moderator on the forum (You can find me by my username born2c0de) and I
will answer your questions on the forums if I happen to come across them.
Please do not email me for help. I will not entertain such emails and if
you wish to receive help from me, please post in the forums.

However, sending Suggestions and Feedback via Email is encouraged.

I hope you've enjoyed reading this tutorial.
Keep visiting for updates.

Is This A Good Question/Topic? 2
  • +

Replies To: File Handling in Visual Basic 6 Part 2 - Binary File Handling

#2 dcorning  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 2
  • Joined: 03-March 09

Posted 03 March 2009 - 11:21 AM

Thanks for this information.

However I want to write the binary file without the additional bytes of data. Example, I want to read data in from a file, change it to some other hex character and then write that single binary byte back out.

Is this something that is easy to do in visual basic 6. Can you give an example of how to write a binary file a single byte at a time, and only the one byte and not with the additional information.

Thanks

David Corning




View Postborn2c0de, on 29 Jun, 2008 - 02:22 AM, said:

FILE HANDLING USING VISUAL BASIC 6.0 PART II - BINARY FILE HANDLING



- Sanchit Karve
born2c0de
printf("I'm a %XR",195936478);


CONTACT ME : born2c0de AT dreamincode DOT net

CONTENTS
  • I. ASSUMPTIONS
  • II. BASIC RELATIONSHIPS
  • III. INTRODUCTION
  • IV. SEQUENTIAL FILES, BINARY MODE, BINARY FILES
  • V. BINARY FILE HANDLING
  • VI. READING AND WRITING IN BINARY MODE
  • VII. ACCESS-LOCKS
  • VIII. Hide and SEEK
  • IX. BINARY FILE HANDLING FUNCTIONS
  • X. BINARY FILE HANDLING EXAMPLES
  • XI. CONTACT ME



I. ASSUMPTIONS

The reader is expected to have read the first part of this tutorial which deals
with sequential files. You can still follow this tutorial without reading Part-I,
but I recommend reading the sequential files tutorial first because I may have mentioned certain things in Part-I which also apply to Binary Files.

II. BASIC RELATIONSHIPS

You might have heard several terms in File Handling such as Fields, Records etc.
but may not know what they mean.
To understand it simply remember this set of relationships:
8 Bits = 1 Byte/Character
Many Bytes/Characters = 1 Field (or String)
Many Fields = 1 Record
Many Records = 1 File
Many Files = 1 Database


III. INTRODUCTION

As far as Visual Basic 6 is concerned, there are three modes in which a file can
be accessed.
  • Text Mode (Sequential Mode)
  • Binary Mode
  • Random Access Mode
In the Text Mode, data is ALWAYS written and retrieved as CHARACTERS.
Hence, any number written in this mode will result in the ASCII Value of the
number being stored.
For Example, The Number 17 is stored as two separate characters "1" and "7".
Which means that 17 is stored as [ 49 55 ] and not as [ 17 ].

In the Binary Mode, everything is written and retrieved as a Number.
Hence, The Number 17 Will be stored as [ 17 ] in this mode and
characters will be represented by their ASCII Value as always.

One major difference between Text Files and Binary Files is that Text Files
support Sequential Reading and Writing. This means that we cannot read or write
from a particular point in a file. The only way of doing this is to read through
all the other entries until you reach the point where you want to 'actually'
start reading.

Binary Mode allows us to write and read anywhere in the file. For example we can
read data directly from the 56th Byte of the file, instead of reading all the
bytes one by one till we reach the 56th byte.

Part-I dealt with Sequential Files, and this one will teach you how to read and
write files in Binary Mode.

IV. SEQUENTIAL FILES, BINARY MODE, BINARY FILES

You will often come across the terms "Text Files", "Sequential Files",
"Sequential Mode", "Binary Mode" and "Binary Files" while reading books,
articles or even posts on the internet related to file handling and wonder what
they really mean.

A file is a set of bytes/records stored together.

Text Files are files which contain only characters in ASCII or Unicode.

Sequential Files are files opened in Sequential Mode.

Sequential Mode refers to any of the modes used for sequential file handling
which are Input, Output and Append.

Binary Mode refers to the Binary Mode [which you shall learn about as you
progress through this tutorial]

Binary Files refer to files opened in Binary Mode.

You should note that Binary Files and Sequential Files are not different kinds
of files but rather different methods of accessing a file.

Any file can be opened in both sequential and binary modes (obviously not at the
same time ;) ). If it is opened in sequential mode, you will only be able to
access data in the file sequentially. If it's opened in Binary mode, you can
access any byte in the file without reading the previous bytes in the file.

V. BINARY FILE HANDLING

Let us start with a very simple example:

'Add a Command Button with name as Command1 onto a Form
Private Sub Command1_Click()
   Dim f As Long
   f = FreeFile()

   Open "c:\test.txt" For Binary As #f
   Close #f
End Sub


As you can see, the FreeFile() function can also be used for binary files.
The Open Statement opens c:\test.txt in Binary Mode and the next statement
closes the file.

As obvious as it may sound, you need to open a file before using it and close it
when you have finished reading or writing to it. Many programmers forget to add
the Close statement which results in the File Already Open Error, and it can be
a pain to track down the exact location that caused the error when you're
dealing with many files.

You should note that this snippet does more than open and close a file.
If the test.txt file is not present in C drive, then it creates a blank file
with the same name.

VI. READING AND WRITING IN BINARY MODE

Now that you know how a file is opened, let us see how we can read and write
data in Binary mode.

Here's an example which writes a string in a Binary File.

'Create a Command Button as Command1
Private Sub Command1_Click()
    Dim f As Long
    f = FreeFile()
    Open "C:\abc.txt" For Binary As #f
    Put #f, , "This is the Test file."
    Close #f
End Sub


The string "This is the Test file." is written to the abc.txt file in the C
drive. The Put Statement is used to write data to a binary file. The Syntax of
Put is as follows:

Put #fileNumber, [startByte], varName


where
#fileNumber = A file handle ('f' is the file handle in the previous example)
startByte = (Optional) Byte position to start writing at.
varName = Variable/Literal whose contents are to be written. varName can be a variable of any data type.

In the above example, we have skipped the second parameter which means that the
string is written at the current position of the file, which in this case is the
beginning of the file. (More on this in Section VIII. Hide and SEEK)

We can choose to write data at a different position by specifying this parameter.
Change the Put Statement from the previous example to Put #f, 13, "B"

Now run the program, quit the program and open the abc.txt file. You will see
that the file now contains "This is the Best file."

The Put statement in this case writes "B" at the 13th byte in the file. You can
see that the 13th position in the file is the letter "T". Hence "T" gets
replaced by "B".

[ NOTE FOR ASSEMBLY, C AND EXPERIENCED VB6 PROGRAMMERS ]
Unlike other languages, VB6 does not store strings in ASCII format. The string
"ABCD" is stored in VB6 like this:
[ 00 08 65 00 66 00 67 00 68 00 ]
The first two bytes contain the length of the following string. The latter
portion of the string uses 2 bytes for every character. Hence the trailing zeros
for every character.

That's right, VB6 stores strings internally in Unicode but what I really want to
tell you is that while the length of this string is actually 10 bytes, when it
is written in a File VB6 ALWAYS STORES IT IN ASCII FORMAT.

For more information on how the VB6 Len() function works, click here to read my
blog post which elucidates the working of the function.



Now coming back to the topic. As you now know, the Put statement is used to
write to a binary file. The Put statement is also used to write to Random Access
Files. (More information on that in Part III of this tutorial)

A logical opposite of Put is Get, and that's what you'll need to use to read
data from a Binary File. Have a look at this fragment of code:

Private Sub Command1_Click()
    Dim f As Long
    Dim x As Byte

    f = FreeFile()
    Open "C:\abc.txt" For Binary As #f

    Get #f, , x
    Close #f

    MsgBox x
End Sub


This will display 84 (ASCII Value of T) in a Message Box. The syntax of the Get
Statement is exactly the same as that of the Put statement. Experiment with the
second parameter and notice how you get ASCII values of the other elements.

Let's try to read in the first word of the file. We know that the first word is
"This", so we'll create a Byte Array of length 4 like this:

Private Sub Command1_Click()
    Dim f As Long
    Dim x(3) As Byte 'Creates Array from Index 0 to 3
    Dim readresult As String

    f = FreeFile()
    Open "C:\abc.txt" For Binary As #f

    Get #f, , x
    Close #f
    readresult = Chr(x(0)) & Chr(x(1)) & Chr(x(2)) & Chr(x(3))
    MsgBox readresult
End Sub


Visual Basic will automatically fill in every element of the array x until it
can't store any more. So it starts from the first position (2nd parameter is not
specified) and copies the first 4 characters into the Byte Array x.

Since the array x is of data type Byte, we need to convert it to a string and
then display it as shown.

But can't we pass a string variable directly to the Get Statement?
Yes, you darn well can. Have a look:

Private Sub Command1_Click()
    Dim f As Long
    Dim readresult As String

    f = FreeFile()
    Open "C:\abc.txt" For Binary As #f

    Get #f, , readresult
    Close #f

    MsgBox readresult
End Sub


The output of this code is totally unexpected. It's null. The Message Box
doesn't display anything. Why is this so?

As I mentioned earlier, the Get statement automatically detects the length of
the string and fills up data into the variable till it can't store any more.

Ring any bells?

What's the length of the readresult string?

It's ZERO because nothing is stored in it initially, and hence nothing will be
stored in it after the Get statement.

To get the code to work as expected, we need to specify the length of the string
by either defining it as a fixed-length string or initializing it to a string of
non-zero length.

You can either define the string as a fixed-length string like this:
Dim readresult As String * 4


or initialize the string to something with its length as 4 like this:
Dim readresult As String
   readresult = String(4, " ") ' or even readresult = "ABCD"


Now, make the appropriate changes in the previous example and run the program.
The Message Box should display "This".

VII. ACCESS-LOCKS

An important point that deserves mention is that unlike sequential files, you
can read and write at the same time in Binary Mode. It is possible to read from
a file in one statement and write to it in the following statement but the same
cannot be done in sequential mode.

Since read and write operations are permitted on an open Binary file, there are
no further modes under Binary. (unlike sequential files which have Input, Append
and Output modes which permit only one operation)

But this isn't advantageous in every situation. Consider a situation where you
wish to ONLY read from a file. What if you write to the file by mistake? In
sequential mode, VB will flag an error saying you can't write in Input mode. But
since read and write operations are permitted in Binary mode, VB won't flag an
error and the file will get modified.

The same situation can occur when multiple users in a networked environment are
accessing the same file. It is quite possible for another user to modify data in
a file while you are reading it, which can lead to unexpected disastrous results.

Thankfully, Visual Basic gives you an option to set the permissions you need for
working on the file.

You can either specify these permissions when you open a file or Lock a
particular set of bytes after you open the file.

The supported Access Locks in VB6 are:
  • Shared : Other Users/Processes can Read and Write to the File even while your program is working on it.
  • Lock Read : No other program is allowed to read the file while you are working on it.
  • Lock Write : No other program is allowed to write to the file while you are working on it.
  • Lock Read Write : Other programs cannot read nor write to the file while you are working on it.
The above mentioned locks set permissions for other users and processes that try
to access the same file.

To set permissions for operations that you are allowed to do on the file, VB6
provides 3 access modes.
  • Read : You can only read the file.
  • Write : You can only write to the file.
  • Read Write : You can read and write to the file.

By using the access permissions and Lock modes, you can prevent your program
from being a victim to your own programming errors and multiple-user access
problems.

To use these permissions, you will need to specify them in the Open statement
like this:
Open <pathname> For Binary [Access] [lock] As #filenumber


where
pathname = Name of File
Access = Read / Write / Read Write
lock = Shared / Lock Read / Lock Write / Lock Read Write

Eg. To open the abc.txt file for read permission such that no other process can
use it while you are working on it your Open statement should look like this:

Open "c:\abc.txt" For Binary Read Shared Read Write As #1


These access permissions are applied on the entire file but you can also
selectively lock certain bytes in a file. The Lock statement enables you to do
this.

The syntax of Lock and Unlock are:

Lock [#]filenumber[, recordrange]

Unlock [#]filenumber[, recordrange]


where recordrange can have 3 types of values.
  • (Optional) i.e. No parameter passed as recordrange.
  • A Byte Position
  • x To y
In the first case if no parameter is specified, the entire file is locked or
unlocked.

If you specify 10 as a byte position (case 2), the file will be locked/unlocked
for all bytes starting from the 10th position.

If you specify 20 To 30 as the parameter (case 3), all bytes from 20 to 30 will
be locked/unlocked.

Examples:
Lock #1
Lock #1, 20
Lock #1, 20 To 40
Unlock #1
Unlock #1, 20
Unlock #1, 20 To 40


CAUTION:
You must use Lock and Unlock in pairs i.e. the arguments must match exactly.
Ensure that unlock every locked file before closing it or quitting your program.
Failure to do so produces unpredictable results.

IMPORTANT NOTE:
Locks and Access Permissions can also be set for Input, Output, Append and
Random Access Modes. However, specifying the byte range in Lock/Unlock for
sequential files still results in the entire file being locked. (It's called a
sequential file for a reason, you dummy!!! ;) )

VIII. Hide and SEEK

Consider a situation where you are interested only in bytes 100 to 110 and wish
to write certain bytes to these positions in a file. How would you go about
writing the Put statement?

Put #1, 100, <Byte1>
Put #1, 100, <Byte2>
...
Put #1, 109, <Byte9>
Put #1, 110, <Byte10>


or

For I = 0 to 10
    Put #1, (100 + i), <Byte_from_Array>
Next I


Yes, you could but there's a better way. VB6 provides a Seek() function and a
Seek statement which allows you to get/set the current position of an open file.

The Syntax of Seek is simple :
Seek #filenumber, BytePosition


You can now write the same code like this:

'Open the file with handle 1
Seek #1, 100
Put #1, , Byte1


The same works for the Get statement as well. You can use Seek() to set the
current position of the file for reading.

NOTE:
Unlike C and other languages which allow you to set different positions for
reading and writing, VB6 considers the same position for reading and writing.

If the second parameter is left blank in Get or Put, it will read/write from/to
the current position of the file specified by the last Seek() function executed.

Consider this snippet:
Seek #1, 100
Put #1, 200, "Hey"


In this case even though we have set the current position of the file to the
100th bit, the Put statement writes "Hey" from the 200th byte. If the second
parameter is specified, Get/Put ignore the position set by Seek().

Seek has another use. If you use Seek as a function, it will return the current
position of the file.
Hence,
Seek #1, 100
Msgbox Seek(1)


will display 100 in a Message Box.

The LOC() function also returns the current position in the file.

IX. BINARY FILE HANDLING FUNCTIONS

VB6 provides many more library functions which you can use for Binary File
Handling. Here's the list of functions that are related to Binary File Handling:
  • FreeFile():
    DESCRIPTION : Returns an Integer representing the nextfile number available
    for use by the Open statement.

    SYNTAX : FreeFile[(rangenumber)]
    The optional rangenumber argument is a Variant that specifies
    the range from which the next free file number is to be
    returned. Specify a 0 (default) to return a file number in the
    range 1 255, inclusive. Specify a 1 to return a file number
    in the range 256 511.

    USE : FreeFile() is used to avoid using a file handle that is already
    in use.

  • EOF():
    DESCRIPTION : Returns an Integer containing the Boolean value True when the
    end of a file has been reached.

    SYNTAX : EOF(filenumber)
    The required filenumber argument is an Integer containing any
    valid file number.

    USE : EOF() is occasionally used in loops to process a file until the
    End of File is reached.

  • FileLen() :
    DESCRIPTION : Returns a Long specifying the length of a file in bytes.

    SYNTAX : FileLen(pathname)
    The required pathname argument is a string expression that
    specifies a file.

    USE : FileLen() is Used to find the length of a file that has not
    been opened using the Open Command.

  • LOF() :
    DESCRIPTION : Returns a Long representing the size, in bytes, of a file
    opened using the Open statement.

    SYNTAX : LOF(filenumber)
    The required filenumber argument is an Integer containing a
    valid file number.

    USE : LOF() is used to find the length of a file when a file is
    currently open.

  • LOC() : *Thanks to Warren Brayshaw for correcting an error*
    DESCRIPTION : Returns a Long representing the read/write position in a file
    opened using the Open statement.

    SYNTAX : LOC(filenumber)
    The required filenumber argument is an Integer containing a
    valid file number.

    USE : LOC() is used to find the current position of the read/write
    pointer in the file.

  • Seek() :
    DESCRIPTION : Returns a Long specifying the current read/write position
    within a file opened using the Open statement.

    SYNTAX : Seek(filenumber)
    The required filenumber argument is an Integer containing a
    valid file number.

    USE : Seek() is used to get the Byte Position where the Next
    Operation will take place.
Along with the above mentioned functions, you can also use "B" character
functions such as AscB(), ChrB(), LeftB(), RightB(), MidB(), InstrB().

The only thing different about these "B" functions is that they work on Binary
Strings (hence the suffix 'B'). These functions have the same syntax as their
original non-B counterparts and is meant to be used in the exact same way.

X. BINARY FILE HANDLING EXAMPLES

Binary File Handling in any language is a very powerful tool in the hands of a
programmer. Use it with caution as even a tiny mistake has the potential to
destroy the entire file.

Binary File Handling is always used in situations where you either wish to
utilize space in the most efficient manner or if you wish to hide information
about the contents of the file or file format. (Microsoft Word files always use
Binary mode to hide the DOC format. Try opening a DOC file in Notepad)

Antivirus Programs also analyze files in Binary Mode. Virus Signatures are
basically a collection of unique bytes. The Antivirus application simply opens
the file in binary mode, seeks to the position of the virus signature (if known),
and searches for the presence of its set of Virus Signatures. A match means that
the file in question is infected with a Virus that has the same Virus Signature.

Although I could give simple code examples like those in Part-I of this tutorial,
I decided to show two very interesting examples using Binary File Handling.
Check them out and Have Fun with them.
  • Detect if a given File is an EXE File.

    Every valid EXE File has "MZ" as its first 2 bytes (known as Magic Number). We
    simply check if the first 2 bytes of a file have "MZ". Rename a file of another
    extension to EXE and test it with the code below.

    Private Function IsValidEXE(ByVal path As String) As Boolean
       On Error Resume Next 'If File Path is invalid
       Dim ret As Boolean
       Dim f As Long
       Dim magic As String * 2
    
       ret = False
       f = FreeFile()
    
       Open path For Binary As #f
       Get #f, , magic
       Close #f
    
       If magic = "MZ" Then ret = True
    
       IsValidEXE = ret
    End Function
    



  • Protect your executable file from being opened by unauthorized users.

    This is a simple trick. All we have to do is change the Magic Number "MZ" of the
    EXE file and change it to something else. Any attempt to run the modified
    executable file will fail. Windows will refuse to run invalid EXE Files.
    To 'unprotect' the file, we simply change it back to "MZ".

    Private Sub ProtectEXE(ByVal path As String)
      Dim f as Long
    
      f = FreeFile()
    
      Open path For Binary As #f
      Put #f, , "SK"
      Close #f
    End Sub
    
    Private Sub UnProtectEXE(ByVal path As String)
      Dim f as Long
    
      f = FreeFile()
    
      Open path For Binary As #f
      Put #f, , "MZ"
      Close #f
    End Sub
    


    CAUTION:
    Please Backup the appropriate file before passing its path to these functions.
    These functions do not damage the file, but it's better to play safe.
XI. CONTACT ME

This concludes the second part of a trilogy of VB6 File Handling Tutorials
written by me. As of this writing, I haven't yet submitted the third and final
tutorial on Random Access Files. I shall write and submit it very soon.

Keep checking the Tutorials Section for updates on the next tutorial.

If you find any errors in the tutorial contact me at born2c0de AT dreamincode DOT net and I'll make the changes immediately.

If you have any questions regarding this tutorial, please add a comment or reply
to this post or post your question on www.dreamincode.net , a programming and
web development community with over 94,000 members to get a prompt answer.
am a Moderator on the forum (You can find me by my username born2c0de) and I
will answer your questions on the forums if I happen to come across them.
Please do not email me for help. I will not entertain such emails and if
you wish to receive help from me, please post in the forums.

However, sending Suggestions and Feedback via Email is encouraged.

I hope you've enjoyed reading this tutorial.
Keep visiting for updates.

Was This Post Helpful? 0
  • +
  • -

#3 griffinmt  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 3
  • Joined: 04-September 10

Posted 04 September 2010 - 07:59 PM

I enjoy scanning thru these tutorials as a refresher to what I thought I used to know :clap:

On the topic of processing binary files, I seem to have a dilema that you could perhaps further discuss.

I have an entire binary file that has been read into a byte array. The file contains a number of data structures, each with ascii text and binary values, and are located within the file based upon the sizes of previous structures.
The layout of a sample structure would be as follows:
Public Type hdr
 id as string * 4
 size as long
 flag1 as byte
 flag2 as byte
End Type
Public Header as hdr
Public FileContent() as byte


It has just been determined that this 'Header' begins at offset 223 into the FileContent array. What is the best way to to get that 'Header' data into the structure - by issuing a get directly into the structure, or by trying to move it from the FileContent array.
The obvious issue is the internal structure of strings vs in the file.
Can you give some further example along the theme?

Thanks
Martyn

This post has been edited by griffinmt: 04 September 2010 - 08:01 PM

Was This Post Helpful? 0
  • +
  • -

Page 1 of 1