Saturday, March 10, 2012

Writing To Text Files

VB.NET provides multiple ways to save program data out to a file. This VB Tutorial will walk you through several different ways to easily save your data to a simple text file. This is by far the most straight forward way to serialize data so that your VB program can later read it back in. Below you will learn how to write to files using both a fixed format or a delaminated format. If you don’t know what this means or why you would choose one over the other please read on and it will make sense.

In another post (about Reading Text Files In VB.NET), we saw how to use the FileStream and StreamReader classes of the System.IO namespace to read a text file in both fixed-length and pipe-delimited formats. We also saw how to use the Input function of the Microsoft.VisualBasic namespace to easily read a comma-delimited file that also contained fields enclosed in quotes.

In this tutorial we will see how to use the FileStream and StreamWriter classes of the System.IO namespace to write a text file in both fixed-length and pipe-delimited formats. We will also see how to use the WriteLine function of the Microsoft.VisualBasic namespace to easily create a comma-delimited file that contains text fields enclosed in quotes; we will also see how to use the PrintLine function of the MS.VB namespace to create a fixed-length file, noting the similarities and differences between that and the StreamWriter technique.

As in the previous section, the file that will be used for all examples in this section is a simplified employee file, which consists of the following fields:

*Please note that the data types for these fields are the data types of the variables into which these fields will be stored.  In the text file, all fields will be represented as a string of characters.

For the fixed-length file, we want to write the records in the following format:

Employee Name (last name first, 20 characters, space-filled on the right)Department Number (up to 4 digits, space-filled on the left)(unused – should contain blank spaces)Job Title (21 characters, space-filled on the right)Hire Date (month/day/year format, 10 characters, space-filled on the right)Hourly Rate (a value between 0 and 99.99, occupies 5 positions, space-filled on the left)

In this example program, the user will be prompted to enter each field on the console, one-by-one (employee name, then department, job title, hire date, and hourly rate). As the user enters each field, the program will check to make sure the data is valid (and if invalid, will show a message and re-prompt for that same field). When all five fields for a record have been entered, the program will write a fixed-length record to the output file and start all over again with the prompts for the next record, beginning with the employee name. If the user presses the Enter key without entering a value for the employee name, this signals the program that the user is done, and the program will end.

A screen-shot of a sample run, where the user has entered two records, is shown below:

image

Looking at the output file in a text editor such as Notepad, we see:

FARLEY,FRANK   123   DBA         1/1/2001  40.00
GARFIELD,GARY  43    IT MANAGER  3/5/1992  60.00

The code for the program is shown below. Note that Sub Main is fairly streamlined, due to the fact that the prompts and data validation for each field are contained in their own functions (GetEmployee, GetDepartment, GetJobTitle, GetHireDate, and GetHourlyRate) which are invoked by Sub Main when needed.

Imports System.IO  Module Module1   Sub Main()  Dim strFileName AsString = My.Application.Info.DirectoryPath _ & "\empout_fixed.txt" Dim objFS AsNew FileStream(strFileName, FileMode.Create, FileAccess.Write) Dim objSW AsNew StreamWriter(objFS) Dim strEmpName AsString Dim intDeptNbr AsInteger Dim strJobTitle AsString Dim dtmHireDate AsDate Dim sngHrlyRate AsSingle  ' Set up an "input loop" to prompt the user for data ... ' "Priming" input: strEmpName = GetEmployeeName()  ' The loop will continue until the user enters a zero-length string for the ' employee name ... DoUntil strEmpName = "" ' Prompt the user for each field ... intDeptNbr = GetDepartment() strJobTitle = GetJobTitle() dtmHireDate = GetHireDate() sngHrlyRate = GetHourlyRate()  ' Write out the record to the file ... objSW.WriteLine(strEmpName.PadRight(20) & _ intDeptNbr.ToString.PadLeft(4) & _ Space(5) & _ strJobTitle.PadRight(21) & _ Format(dtmHireDate, "M/d/yyyy").PadRight(10) & _ Format(sngHrlyRate, "Standard").PadLeft(5)) Console.WriteLine("Record was written to the output file.") Console.WriteLine("") ' Start a new record by prompting for the employee name ... strEmpName = GetEmployeeName() Loop  objSW.Close() Console.WriteLine("") Console.WriteLine("File creation complete. Press Enter to close this window.") Console.ReadLine()  EndSub  PrivateFunction GetEmployeeName() AsString Dim strTest AsString Dim blnValidInput AsBoolean  Do Console.Write("Enter Employee Name (1-20 characters / nothing to quit): ") strTest = Console.ReadLine() strTest.Trim() blnValidInput = True If strTest.Length > 20 Then blnValidInput = False Console.WriteLine("Invalid employee name.") EndIf LoopUntil blnValidInput  Return (strTest) EndFunction  PrivateFunction GetDepartment() AsInteger Dim strTest AsString Dim blnValidInput AsBoolean Dim intX AsInteger Do Console.Write("Enter Dept (1 to 4 digits): ") strTest = Console.ReadLine() blnValidInput = True If strTest.Length < 1 Or strTest.Length > 4 Then blnValidInput = False Else For intX = 0 To (strTest.Length - 1) IfNot (Char.IsDigit(strTest.Chars(intX))) Then blnValidInput = False ExitFor EndIf Next EndIf IfNot blnValidInput Then Console.WriteLine("Invalid department number.") EndIf LoopUntil blnValidInput Return (CInt(strTest)) EndFunction  PrivateFunction GetJobTitle() AsString Dim strTest AsString Dim blnValidInput AsBoolean  Do Console.Write("Enter Job Title (1 to 21 characters): ") strTest = Console.ReadLine() blnValidInput = True If strTest.Length < 1 Or strTest.Length > 21 Then Console.WriteLine("Invalid job title.") blnValidInput = False EndIf LoopUntil blnValidInput Return (strTest) EndFunction  PrivateFunction GetHireDate() AsDate Dim strTest AsString Dim blnValidInput AsBoolean  Do Console.Write("Enter Hire Date (month/day/year): ") strTest = Console.ReadLine() blnValidInput = True IfNot IsDate(strTest) Then Console.WriteLine("Invalid hire date.") blnValidInput = False EndIf LoopUntil blnValidInput  Return (CDate(strTest)) EndFunction  PrivateFunction GetHourlyRate() AsSingle Dim strTest AsString Dim blnValidInput AsBoolean  Do Console.Write("Enter Hourly Rate (0 to 99.99): ") strTest = Console.ReadLine() blnValidInput = True  IfNot IsNumeric(strTest) Then blnValidInput = False ElseIf Val(strTest) < 0 Or Val(strTest) > 99.99 Then blnValidInput = False EndIf  IfNot blnValidInput Then Console.WriteLine("Invalid hourly rate.") EndIf LoopUntil blnValidInput  Return (CSng(strTest)) EndFunctionEnd Module

A synopsis of the code follows:

Note that first, your program must import the System.IO namespace. In the Main procedure, the variable to hold the full path and filename of the output file is declared and initialized (note that the location of the file is My.Application.Info.DirectoryPath which, as discussed in the previous section, refers to the directory in which your program is running, normally \bin\Debug in your application directory). The name of the file is "empout_fixed.txt". The FileStream object is the established to hold a reference to the file (note that it is declared in "Create" mode with "Write" access). Then, the StreamWriter object is declared.

The StreamWriter class is used to write a stream of characters. In the .NET framework, a stream, in general terms, is the flow of data from one location to another. In the case of these examples, a stream refers to the text file that will be processed by the sample programs. The syntax for declaring a StreamWriter object is:

       Dim variable As New StreamReader(stream)

where stream is an object representing the stream of characters to be written (in this case a text file).

Variables to hold the data fields are then declared. The processing starts with a "priming" input outside the main loop. This calls the GetEmployeeName function which will prompt the user for the employee name and return the string entered. The loop's termination condition tests whether the name entered is a zero-length string. As long as the user entered "something", the loop will continue. In the loop, prompts are made and input is validated and returned for the department, job title, hire date, and hourly rate fields by calling the GetDepartment, GetJobTitle, GetHireDate, and GetHourlyRate functions, respectively. The fixed-length record is written to the file by the WriteLine method of the StreamWriter object (which was defined with the variable name objSW). The string that is passed to the method is a concatenation of the variables holding the values for the data fields, padded and formatted appropriately. A message is displayed on the console telling the user that the record was written, then the GetEmployeeName function is called as the last statement of the loop, which prompts the user for the employee name, for another possible pass through the loop to write another record. When the user finally responds to the employee name prompt with just the Enter key, the loop ends, we close the StreamWriter object and let the user know the writing of the file is complete.

Download this for VB.NET example: Writing Fixed Length Example

In the second example, a file with pipe-delimited fields is produced. Using the same data entered in Example 1, an inspection of the output file in a text editor such as Notepad would show:

FARLEY,FRANK|123|DBA|1/1/2001|40
GARFIELD,GARY|43|IT MANAGER|3/5/1992|60

The code for the Example 2 program is identical to that of Example 1, except that the output file is named "empout_pipe.txt":

Dim strFileName AsString = My.Application.Info.DirectoryPath _ & "\empout_pipe.txt"

and in the objSW.WriteLine statement, the string that is passed consists of the variables holding the values for the data fields, formatted as necessary, concatenated with the pipe character ("|"):

objSW.WriteLine(strEmpName & "|" & _ intDeptNbr.ToString & "|" & _ strJobTitle & "|" & _ Format(dtmHireDate, "M/d/yyyy") & "|" & _ sngHrlyRate.ToString)

Download the VB.NET code for this example: Pipe Deliminated File Writing

In the third example, a file with comma-delimited fields is produced. String fields in this file will also be enclosed in quotes. Using the same data entered in Example 1, an inspection of the output file in a text editor such as Notepad would show:

"FARLEY,FRANK",123,"DBA","1/1/2001",40
"GARFIELD,GARY",43,"IT MANAGER","3/5/1992",60

This example uses the Microsoft.VisualBasic namespace functions for all I/O, so the System.IO namespace need not be included. The function that produces the output record is WriteLine (not to be confused with the WriteLine method of the System.IO StreamWriter class – in the MS.VB namespace, the WriteLine function is a retooled version of the Write statement from pre-.NET versions of Visual Basic).

The syntax of the MS.VB namespace WriteLine function, as it is used in this example is:

       WriteLine (filenumber[, expression1[, expression2 ...[, expression n]]])

where filenumber is the file number referenced used to open the file with the FileOpen function, and expression1 through expression n is the list of expressions (variables, constants, etc.) that are to be written to the output file. When executed, the items in the expression list are automatically written to the file with commas separating the expressions for each other; and string items are automatically enclosed in quotes.

It should be noted that files written with the WriteLine function are most commonly read back with the Input function. Also note that while we are treating the Hire Date field as a string, the WriteLine function can write a "date" expression to a text file, in which case the date would be written to the file in yyyy-mm-dd format and would be enclosed in pound signs (#) rather than quotes; and if the file is read back with the Input function, the Input function would recognize a field enclosed with pound signs as a date data type.

The code for the Sub Main portion of Example 3 is shown below:

Sub Main()  Dim strFileName AsString = My.Application.Info.DirectoryPath _ & "\empout_comma.txt" Dim intFileNbr AsInteger = FreeFile() Dim strEmpName AsString Dim intDeptNbr AsInteger Dim strJobTitle AsString Dim dtmHireDate AsDate Dim sngHrlyRate AsSingle  FileOpen(intFileNbr, strFileName, OpenMode.Output, OpenAccess.Write)  ' Set up an "input loop" to prompt the user for data ... ' "Priming" input: strEmpName = GetEmployeeName()  ' The loop will continue until the user enters a zero-length string for the ' employee name ... DoUntil strEmpName = "" ' Prompt the user for each field ... intDeptNbr = GetDepartment() strJobTitle = GetJobTitle() dtmHireDate = GetHireDate() sngHrlyRate = GetHourlyRate() ' Write out the record to the file ... WriteLine(intFileNbr, _ strEmpName, _ intDeptNbr, _ strJobTitle, _ Format(dtmHireDate, "M/d/yyyy"), _ sngHrlyRate) Console.WriteLine("Record was written to the output file.") Console.WriteLine("") ' Start a new record by prompting for the employee name ... strEmpName = GetEmployeeName() Loop  FileClose(intFileNbr)  Console.WriteLine("") Console.WriteLine("File creation complete. Press Enter to close this window.") Console.ReadLine() EndSub

    The GetEmployee, GetDepartment, GetJobTitle, GetHireDate, and GetHourlyRate functions referenced in code above are exactly the same as in the previous examples.

A synopsis of the code follows:

The flow of this program is identical to that of the previous examples, but we are using all MS.VB namespace functions instead of the System.IO FileStream and StreamWriter classes. In the Main procedure, the variable to hold the full path and filename of the output file is declared and initialized (in this example, the filename is "empout_comma.txt"). An Integer  variable to hold the filenumber is declared and initialized with the FreeFile function. Variables to hold the data fields are then declared. The file is then opened with the FileOpen function using output mode with write access.

As in the previous examples, the processing starts with a "priming" input outside the main loop. This calls the GetEmployeeName function which will prompt the user for the employee name and return the string entered. The loop's termination condition tests whether the name entered is a zero-length string. As long as the user entered "something", the loop will continue. In the loop, prompts are made and input is validated and returned for the department, job title, hire date, and hourly rate fields by calling the GetDepartment, GetJobTitle, GetHireDate, and GetHourlyRate functions, respectively. The comma-delimited record is then written to the file with the WriteLine function, passing it the filenumber followed by the list of variables holding the data fields. A message is displayed on the console telling the user that the record was written, then the GetEmployeeName function is called as the last statement of the loop, which prompts the user for the employee name, for another possible pass through the loop to write another record. When the user finally responds to the employee name prompt with just the Enter key, the loop ends, we close the file using the FileClose function, and let the user know the writing of the file is complete.

Donwload the VB.NET source for this example: Write Comma Delimited Files

This example uses the MS.VB namespace PrintLine function to produce a fixed-length file. The output is identical to that produced in the first example:

FARLEY,FRANK         123     DBA                  1/1/2001  40.00
GARFIELD,GARY         43     IT MANAGER           3/5/1992  60.00

The syntax of the MS.VB namespace PrintLine function, as it is used in this example is:

       PrintLine (filenumber[, expression1[, expression2 ...[, expression n]]])

where filenumber is the file number referenced used to open the file with the FileOpen function, and expression1 through expression n is the list of expressions (variables, constants, etc.) that are to be written to the output file. However, unlike the WriteLine function, no automatic formatting of the data occurs; each item in the expression list is written adjacent to each other with no added separation characters or quotes. In that PrintLine is a retooled version of the Print statement found in pre-.NET versions of VB, there are two built-in functions that can be used within the PrintLine expression list: TAB and SPC.

SPC(n) simply inserts n number of blank spaces into the output line being built. So the statement PrintLine (1, "ABC", SPC(5), "DEF") would result in a line written to the output file containing "ABC", followed by five blank spaces, followed by "DEF".

TAB(n) is actually a directive that tells PrintLine to position the next output item at position n in the output line. So the statement PrintLine (1, "ABC", TAB(20), "DEF") would result in a line written to the output file containing "ABC", followed by 16 blank spaces, followed by "DEF". This is because first, "ABC" would be written, occupying the first three positions – then TAB(20) says to skip to position 20 in the output line and write "DEF". So 16 positions needed to be bypassed (actually space-padded) to give the 19 positions prior to the 20th where "DEF" would start.

The code for the Example 4 program is identical to that of Example 3, except that the output file is named "empout_fixed_pl.txt":

Dim strFileName AsString = My.Application.Info.DirectoryPath _ & "\empout_fixed_pl.txt"

and the PrintLine function is used instead of the WriteLine function:

PrintLine(intFileNbr, _ strEmpName, _ TAB(21), _ intDeptNbr.ToString.PadLeft(4), _ SPC(5), _ strJobTitle, _ TAB(51), _ Format(dtmHireDate, "M/d/yyyy"), _ TAB(61), _ Format(sngHrlyRate, "Standard").PadLeft(5))

Download the VB.NET code for this example: Fixed Length With PrintLine

This article was original written by The VB Programmer.


View the original article here

No comments:

Post a Comment