Simple File I/O with Visual Basic

File input and output (or file I/O) involves retrieving data (the input) from a file for use in your program. New data created by your program, or existing data that has been modified by your program, is the program's output. This output data may be stored in the same file, or in a new file. The commands available to the programmer for file I/O include those required to open and close files, read data from a file, and write the results of any data processing back to a file.

The data files we will be working with here will be text files. Text files can be used to store fairly large blocks of text (for example, a short story, a letter, or a poem). We are more interested here, however, in text files that can store records. A record is a single line in a file that consists of one or more fields. A customer record, for example, could contain the fields CustomerName, StreetAddress, Town and TelNumber.

In text-based data files, the fields in a record are usually comma-delimited (i.e. each field is separated from the next by a comma). A typical file processing operation opens a file, reads the records into memory and processes them one at a time. The results of this processing are normally output to the screen. Once all of the required records have been read from the file, the file is closed.

If records have been modified by a program, the amended records are usually either written back to the same file, or to a another file. Writing data to a file is a separate operation in which the file must be re-opened, or a new file created. If amended records are written back to the same file, the original version of each record will be replaced (overwritten) by the new version. If new data is being added to a file, the records will be added (appended) to the end of the file, and the existing data will be preserved.

The act of opening a file and reading the records it contains into memory can be described as pre-processing, because this action prepares the records for processing. When records are read from a file, they are accessed sequentially (one after the other), in whatever order they happen to be stored in within the file. Sequential input from a file is called a data stream.

We are now going to create a simple program to read data from a text file and display the data in a text box.

  1. Create a new project called FileReader and create an interface with a RichTextBox control and two buttons, as shown below.

The FileReader program interface

The FileReader program interface


  1. Save the project to create the project folder.
  2. Download the file country.zip from the link below, and unzip the contents into either the \bin\Debug\net6.0-windows or \bin\Debug\net7.0-windows sub-directory of your project folder, depending on which framework you chose for the project. The .zip file contains a file called country.dat.

Download the file country.zip

  1. Set the control names as shown in the table below.

FileReader Form Controls
ControlName
FormfrmFileReader
RichTextBox1rtbOutput
Button1cmdRead
Button2cmdExit

  1. In the Solution Explorer window, right click on the project name ("FileReader") and select Properties from the drop-down menu. The application's Properties window will appear. Scroll down to the Startup Object property, and use the drop-down menu to select FileReader.frmFileReader.
  2. In the form design window, double-click on the cmdRead button and add the following code:

Dim srdFile As IO.StreamReader
Dim strLine As String

rtbOutput.Clear()
srdFile = New IO.StreamReader("country.dat")
Do Until srdFile.Peek = -1
  strLine = srdFile.ReadLine()
  rtbOutput.AppendText (strLine & vbCrLf)
Loop
srdFile.Close()

  1. Double-click on the cmdExit button and add the following command at the cursor:

End

Your code should now look like the screenshot below.


The FileReader program code

The FileReader program code


The first line of code declares a variable of type IO.StreamReader. This is one of the standard classes defined within Visual Basic's System.IO namespace, and as the name suggests it includes methods for reading data from files. The second line of code declares a string variable called strLine which will hold each line of text read from the file.

In the next line of code, the command rtbOutput.clear() calls the RichTextBox object's clear() procedure to clear any pre-existing contents from the box. The fourth line of code uses the New keyword to allocate memory to the variable srdFile (it essentially creates a new instance of a StreamReader object), associates it with the file country.dat, and opens the file for input.

Providing the country.dat file is in the correct sub-directory of your project folder, the program will be able to find it. If you were to move the file to a different folder, you would need to add the drive and path information in order to enable the program to find it.

The Do . . . Until loop iterates through the instructions contained within it until the exit condition is met. The exit condition in this case is when the StreamReader object's Peek method detects the end of the file (in which case it returns a value of -1). Each iteration of the loop reads one line of the file into the strLine variable using the StreamReader object's ReadLine() method, and appends the data to the output displayed by the RichTextBox object, using that object's AppendText() method.

Note that the command rtbOutput.AppendText(strLine & vbCrLf) also appends a newline character (represented by the Visual Basic constant vbCrLf) to each line of text to be displayed. The last line of code for the cmdRead button's Click event uses the StreamReader object's close() method to close the file. When you have finished working with a file, you should always close it.

If you run the program and click on the Read File button, you should see something like the following screenshot:


The FileReader program output

The FileReader program output


Reading a text file one line at a time is relatively easy, as we have seen. When each line in the file is a record consisting of multiple fields, we need to do some more work in order to extract the information from each field and display it in the correct format. The fields in such a file are usually separated by a comma and are often referred to as comma-separated values. For this reason, files that contain data in this format often have the extension ".csv".

To demonstrate how data in a comma separated value file is processed, we will create an application to read and display the contents of a file that contains league table information for the Barclays Premier League. The file league_table.csv can be downloaded here.

The records in the file are preceded by a header on the first line giving the date on which the information was published. Each record in the file consists of the name of a Premier League team, the number of games played, the number of games won, the number of games drawn, the number of games lost, and the total number of points achieved to date. We are going to create a program to read the file and display the contents in an appropriate format.

  1. Create a new project called LeagueTable and create an interface with a RichTextBox control, as shown below.

The LeagueTable program interface

The LeagueTable program interface


  1. Save the project to create the project folder.
  2. Download the league_table.csv file from the link above if you have not already done so, and save it to the \bin\Debug\net6.0-windows or \bin\Debug\net7.0-windows sub-directory of your project folder, depending on which framework you chose for the project.
  3. Set the Font property of the RichTextBox control to "Courier New, 8.25pt"
  4. Set the control names as shown in the table below.

LeagueTable Form Controls
ControlName
FormfrmLeagueTable
Label1lblTitle
Label2lblDate
RichTextBox1rtbOutput
Button1cmdDisplayInfo
Button2cmdExit

  1. Open the application's Properties window, scroll down to the Startup Object property, and change the this property to LeagueTable.frmLeagueTable.
  2. In the form design window, double-click on the cmdDisplayInfo button and add the following code at the cursor:

Dim srdFile As IO.StreamReader
Dim strRec() As String
Dim strLine As String

srdFile = New IO.StreamReader("league_table.csv")
strLine = srdFile.ReadLine
lblDate.Text = "Date: " & strLine
rtbOutput.Clear()
rtbOutput.AppendText _
  ("Team         Played    Won   Drawn    Lost  Points" _
    & vbCrLf & vbCrLf)
Do Until srdFile.Peek = -1
  strLine = srdFile.ReadLine
  strRec = strLine.Split(",")
  rtbOutput.AppendText(strRec(0).PadRight(15) & _
    strRec(1).PadRight(8) & strRec(2).PadRight(8) _
    & strRec(3).PadRight(8) & strRec(4).PadRight(8) & _
    strRec(5).PadRight(8) & vbCrLf)
Loop
srdFile.Close()

  1. Double-click on the cmdExit button and add the following command:

End

Your code editor window should now look like the screenshot below.


The LeagueTable program code

The LeagueTable program code


Here is the output from the LeagueTable program:


The LeagueTable program output

The LeagueTable program output


As in the previous program, we have declared a string variable called strLine to hold the contents of each line of text read from the file. Since each line of text is actually a record consisting of comma-delimited fields, we want to be able to access the data in each field without having to write complex procedures for extracting each field from the input string (a process referred to as parsing). We do this using the Split() method provided for Visual Basic strings, which breaks a string into its constituent substrings with reference to a specific delimiter symbol (in this case a comma) which is passed to the Split() method as a parameter.

The variable strRec() is declared as an empty array of type String, into which we can place the field data from each record. The string values returned by Split() will become the array elements within the strRec() array variable, and can be referenced using the array subscripts 0 - 5.

The code preceding the Do . . . Until loop creates the StreamReader object and reads in the first line of the file (the date information), which is then displayed at the top of the form. The RichTextBox is cleared (as for the FileReader program), and the column headings for the data are displayed.

The loop iterates until the end of the file is encountered. On each iteration, one record is read from the file and is assigned to the six-element strRec() array after being split into its constituent fields. Each array element is then appended to the RichTextBox output, and the newline character (represented by the Visual Basic constant vbNewLine) is appended to each line of output.

The PadRight() method ensures that each array element occupies the same number of text columns, and that the output is vertically aligned. The StreamReader class defines a number of methods for handling file input. The most commonly used methods, including those we have already used, are summarised below.


StreamReader Methods
NameDescription
CloseCloses the StreamReader object and its stream, and releases system resources associated with it.
PeekReturns the next available character without advancing the file pointer.
ReadReads the next character from the input stream and advances the file pointer by one character.
ReadLineReads a line of characters from the input stream and returns the data as a string.
ReadToEndReads all data in the input stream from the current position to the end of the stream.


We have already mentioned that the data in a file is accessed sequentially as a stream of bytes. As the program reads each item of data in a file, it moves a special placeholder called a file pointer to the start of the next data item so that it can keep track of where it is in the file. This is a bit like putting a bookmark in a book when you put it down, so that you know where to start reading the next time you pick up the book.

A data file is usually loaded into memory from a secondary storage device in its entirety. Low-level file-access operations, on the other hand, read the file one byte at a time once it is in memory, advancing the file pointer to the start of the next byte each time they perform a read operation. The end of a line of text in a file is marked by a special character called a newline character. Methods like ReadLine use that fact to read all of the characters in a line of text into a buffer until they encounter the newline character, at which point they stop reading characters.

The end of file character signals the end of the file, enabling the Peek method (which reads the next character in the file without moving the file pointer) to detect an end-of-file condition.

So far we have read data from a file and displayed it on the screen, but the data has to get into the file in the first place. This is achieved by using an application that accepts user input (or date retrieved from another file) , and writes it to an output file. The data may also undergo some kind of processing before it is written to the output file.

We will create a simple program that accepts user input and writes it to a text file as a series of comma separated values. The program will record data about the highest temperatures recorded for some of Western Europe's capital cities throughout the year 2010.

  1. Create a new project called Temperatures and create an interface like the one shown below.

The Temperatures program interface

The Temperatures program interface


  1. Save the project to create the project folder.
  2. Set the control names as shown in the table below.

Temperatures Form Controls
ControlName
Form1frmTemperatures
TextBox1txtCity
TextBox2txtJan
TextBox3txtApr
TextBox4txtJul
TextBox5txtOct
Button1cmdEnterData
Button2cmdDisplayData
Button3cmdExit

  1. Open the application's Properties window, scroll down to the Startup Object property, and change the this property to Temperatures.frmTemperatures.
  2. In the form design window, double-click on the cmdEnterData button and add the following code:

Dim swrFile As IO.StreamWriter
Dim strLine As String
strLine = txtCity.Text & "," & txtJan.Text & "," & _
  txtApr.Text & "," & TxtJul.Text & "," & txtOct.Text
swrFile = IO.File.AppendText ("temperature.csv")
txtCity.Clear()
txtJan.Clear()
txtApr.Clear()
txtJul.Clear()
txtOct.Clear()
swrFile.WriteLine(strLine)
swrFile.Close()

The first line of code declares a variable of type IO.StreamWriter. This is another one of the standard classes defined within Visual Basic's System.IO namespace, and as the name suggests it includes methods for writing data to files.

The second line of code declares a string variable called strLine which will hold each record to be written to the file as a string containing comma-delimited field values.

The third line of code concatenates the input data entered by the user into the various text boxes into the strLine string variable. The fourth line of code opens a file called temperatures.csv and associates it with the swrFile object.

Note that the file is opened in append mode. This means that if the file already exists, the file pointer will be set to the end of the file so that new data is added (appended) to the file. Any existing data is preserved, and is not overwritten. If the file does not exist, it is created.

The next five lines of code clear the text boxes for the next item of input data. The penultimate line writes the comma-delimited record stored in strLine to the file, and the last line closes the file once more.

  1. Double-click on the cmdDisplayData button and add the following command at the cursor:

Dim srdFile As IO.StreamReader
Dim strfile As String
srdFile = New IO.StreamReader("temperature.csv")
strfile = srdFile.ReadToEnd
MsgBox(strfile)
srdFile.Close()

  1. Double-click on the cmdExit button and add the following command at the cursor:

End

Your code editor window should now look like the screenshot below.


The Temperature program code

The Temperature program code


The code for the cmdDisplayData button is very similar to some of the code you have seen previously, except that we have used the StreamWriter object's ReadToEnd() method to read all of the data in the file into a string variable (strFile). The resulting string is subsequently displayed in a message box. Test the program by entering temperature data from the table below into the program one record at a time, and clicking on the Display data button.


Maximum Temperatures (°F) in European Cities (2010)
CityJanAprJulOct
Amsterdam41536957
Athens54679074
Berlin35557455
Copenhagen36507253
Dublin47546757
Glasgow43536654
Helsinki27437145
Lisbon56647969
London44567358
Madrid50638967
Oslo30507349
Paris42607659
Rome54688873
Stockholm31457048
Vienna34577555
Zurich36607757


The StreamWriter class defines numerous methods for handling file output. Some of these methods, including the ones we have already seen, are summarised below.


StreamWriter Methods
NameDescription
CloseCloses the StreamWriter object and its stream.
Write(Boolean)Writes the text representation of a Boolean value to a text stream.
Write(Char)Writes a character to a text stream.
Write(Char())Writes a character array to a text stream.
Write(Decimal)Writes the text representation of a decimal value to a text stream.
Write(Double)Writes the text representation of an 8-byte floating-point value to a text stream.
Write(Int32)Writes the text representation of a 4-byte signed integer to a text stream.
Write(Int64)Writes the text representation of an 8-byte signed integer to a text stream.
Write(Single)Writes the text representation of a 4-byte floating-point value to a text stream.
Write(String)Writes a string to a text stream.
Write(UInt32)Writes the text representation of a 4-byte unsigned integer to a text stream.
Write(UInt64)Writes the text representation of an 8-byte unsigned integer to a text stream.
WriteLineWrites a line terminator to a text stream.