Up to this point we have shown how to access the file system using classes provided by the .NET framework. However, there is another group of file-related functions that have been around since early versions of Visual Basic (and in some cases, the original BASIC language). If you work with a lot of existing Visual Basic code, you may run into these traditional file I/O functions. These functions are still supported via a compatibility namespace, although there are some changes to their syntax in Visual Basic .NET. We recommend you use the newer object-oriented classes whenever possible, but if you need to work with existing code you may find this section helpful. Before using any of these functions, add the following Imports statement to your code: Imports Microsoft.VisualBasic.FileSystem Using Dir to Find Files One useful file function is the Dir function. This function works just like the dir command at an MS-DOS command prompt. You can use it to retrieve a list of one or more operating system files that match a path and file specification. For example, C:\*.BAT is the path to all the files in the root directory of drive C having a BAT extension. The syntax of the Dir function is as follows: stringvar= Dir(path[,attributes]) One common use of Dir is to determine whether a file exists. The function returns the filename without the full path if the specified file is found, or it returns an empty string if no files were found. The following code example uses Dir to check for the existence of a file: Public Function bFileExists(sFile As String) As Boolean If Dir(sFile) <> "" Then bFileExists = True Else bFileExists = False End Function This function could then be used to check any filenames passed to the program by the user, as in the following example: Dim sUserFile As String sUserFile = InputBox("Enter the file name:") If Not bFileExists(sUserFile) Then MessageBox.Show("The file does not exist. Please try again.") Application.Exit() End If Another use of the Dir function is to return a list of multiple files in the specified path. If you use the dir command at an MS-DOS prompt, each matching file is listed on the screen. However, because the Dir function is designed to return only a single string variable, you have to use a loop and retrieve one filename at a time. Suppose that your C:\DATA directory contains several picture files with a BMP (bitmap) extension. The path used to retrieve these files with the Dir function would be C:\DATA\*.BMP. You can use the following lines of code to retrieve the filenames and add them to a listbox: Dim sNextFile As String sNextFile = Dir("C:\Data\*.BMP") While sNextFile <> "" lstPictureList.Items.Add(sNextFile) sNextFile = Dir() End While In the preceding example, notice that only the file path to Dir is supplied on the first call. Each subsequent call to Dir has no arguments, indicating that you want to use the previous file path and move to the next filename in the list. When no more files match, Dir returns an empty string and the While loop terminates. The second, optional parameter of the Dir function is used to provide additional conditions (beyond the specified path) with which to select files. You add together constants defined in FileAttributes to control the types of files returned. For example, the following statement causes subdirectories and files that start with the letter S to be returned: sNextFile = Dir("C:\Data\S*",FileAttribute.Directory) The available constants and their purposes are listed under the help file topic "FileAttributes Enumeration." File Manipulation Functions As with the Dir function, most of the file-manipulation commands in Visual Basic are as straightforward as their MS-DOS equivalents, although with a few limitations. These commands are summarized in Table 24.5. Table 24.5. Summary of File Functions Action | Syntax |
---|
Copy a file | FileCopy source, dest | Delete one or more files | Kill path | Create a new folder | MkDir pathname | Remove an empty folder | RmDir pathname | Change current directory | ChDir pathname | Change current drive | ChDrive drive | The FileCopy command has the limitation that you cannot use wildcards to specify multiple files. FileCopy can copy files locally or over a network, as shown in the following examples: 'The following line copies a file while changing its name: FileCopy ("D:\My Documents\Hey Now.txt", "C:\DATA\TEST.TXT") 'The following lines of code use a network path for the source file: Dim sDest As String = "\\myserver\deptfiles\budget98.XLS" Dim sSource As String = "C:\DATA\BUDGET.XLS" FileCopy sSource, sDest The FileCopy statement automatically overwrites an existing file, unless the file is read-only or locked open by another application. Note The older Name and App.Path functions have been replaced by the newer File.Move and Application.StartupPath methods. Sequential Text Files Visual Basic's file input and output routines allow you to read and write sequential text data. Before you read or write information, you must open the file with the FileOpen function. The FileOpen statement associates the actual filename (that is, C:\DATA\PEOPLE.TXT) with a file number. A file number is an integer value used to identify the file in subsequent lines of code: FileOpen(1, "C:\Data\People.txt", OpenMode.Input) Note In the preceding example, 1 is the file number. However, if you open and close multiple files throughout your program, using this number might not be a good idea. In that case, you should use the FreeFile function, which returns the next available file number, as in the following example: Dim FileNum As Integer FileNum = FreeFile() FileOpen(FileNum, "C:\Temp\quotes.txt", OpenMode.Input) In addition to providing the filename and number association, the FileOpen statement tells Visual Basic how you intend to use the specified file. (Many different options are available with FileOpen, as discussed in the Help file.) The Mode parameter is set to OpenMode.Input to indicate that the file will be opened for sequential input. The following code uses a LineInput statement in a While loop to read the file one line at a time. A line in a file is delimited by an end of line marker, which in Windows is the carriage return character followed by the line feed character. The first LineInput statement reads the first line, the second LineInput reads the second line, and so on. Dim FileNum As Integer Dim TempString As String FileNum = FreeFile() FileOpen(FileNum, "C:\temp\output.xml", OpenMode.Input) While Not EOF(FileNum) TempString = LineInput(FileNum) lstFiles.Items.Add(TempString) End While FileClose(FileNum) If you try to read more lines of text than are in the file, an error occurs. Therefore, the sample code uses the EOF (end-of-file) function before attempting to read. Note VB6 users will notice the old-style file commands have been altered slightly in VB .NET. For example, the Line Input statement is now the LineInput function. Also, the following type of Open syntax is no longer supported: Open "C:\File.txt" for Input as #1 'THIS WILL NOT WORK ANYMORE! After you open the file, you can choose from several methods of reading information from it. In the example, each line was considered one piece of information, so no further processing on the string variable was done. However, sometimes you may want to read less than a whole line or store more than one piece of information on a single line. In these cases, you can use the Input function. Note Visual Basic provides a lot of nice string-manipulation functions. Again, the authors would like to suggest that for new projects, you use the object-oriented file functions. The Inputfunction is designed to read information stored in a delimited fashion. For example, the following line of a text file contains three distinct pieces of information: a string, a number, and a date. Commas, quotation marks, and the # symbol are used to delimit the information. "Test",100,#1998-01-01.htm# The following lines of code read each item into an appropriately typed variable: Dim TempString As String Dim TempDate As DateTime Dim TempInt As Integer FileNum = FreeFile() FileOpen(FileNum, "C:\Temp\test.txt", OpenMode.Input) Input(FileNum, TempString) Input(FileNum, TempInt) Input(FileNum, TempDate) FileClose(FileNum) Remember that the Input function looks for delimiters, so exceptions will be thrown if your Input statements do not match the format of the file. After you finish using a file, you should always close it with the FileClose function. This way, you can free up the file number for use with other files. If you do not specify a file number, Close closes all open file handles. One good use of a sequential text file is a log file. For example, I have a scheduler application that runs programs and database updates. I rarely work at the machine on which the scheduler application is running, but I can connect over the network and view the log file to see whether the updates have completed. As with the newer object-oriented file functions, the FileOpen method supports both append and output modes. Compare the following two lines of code, each of which opens a file for output: 'Append mode adds to an existing file or creates a new one FileOpen(FileNum, Application.StartupPath & "\errorlog.txt", OpenMode.Append) 'Output Mode always creates a new file, erases any existing information FileOpen(FileNum, Application.StartupPath & "\errorlog.txt", OpenMode.Output) Append mode means data written to the file is added to the end of any existing data. This is perfect for the log file application because you want to keep adding to the log file. Opening a file for Output means that any existing data will be erased. In either case, the Open statement automatically creates the file if it does not exist. After a file has been opened for Output, you can use the Print or PrintLine statements to write string information to it. The PrintLine method inserts a new line character after the text. Two other functions, Write and WriteLine, automatically add separators and delimiters. They are intended for use with the Input function described earlier. An example of the use of the WriteLinefunction is: WriteLine(FileNum, "This is a Write Example", #12/10/1972.htm#, 100 * 2) The line that would be written to the file looks like this: "This is a Write Example",#1972-12-10#,200 As you can see, the Print functions give you more control over output format, whereas the Write functions add delimiters for easy retrieval of information. Understanding INI Files INI files (pronounced any files by us southerners) are useful for storing program information and user settings. An INI file is basically a text file with a simple structure that allows you to save and retrieve specific pieces of information; its filename extension is INI, short for initialization. By storing information in an INI file, you can avoid hard-coding values in your program. This way, you can easily change values without recompiling the program. The structure of INI files is simple. INI files can be viewed and edited with Notepad, or any other text editor. A sample INI file is shown in Figure 24.7. Figure 24.7. Although Microsoft's direction seems to be using XML for everything, an INI file provides a portable and easy-to-understand configuration file format. The three elements to an INI file are sections, keys, and values. (Microsoft calls a section an application; the reason for this involves the history of INI files when an application stored its own settings in WIN.INI.) The descriptions of these parts are summarized in Table 24.6. Table 24.6. Parts of an INI File Element | Description |
---|
Section | A name enclosed in brackets ([ ]} that groups a set of values and keys together. | Key | A unique string. The key will be followed by an equal sign (=) and a value. A key needs to be unique only within a specific section. | Value | The actual information from a particular key in the INI file. A section and key together are used to read or write a value. | The order of sections and keys within the file is not important because the section and key names (should) point to only one value. One final note on the structure of an INI file: A semicolon (;) is used to indicate a comment; any keys or values following a semicolon are ignored. For example, look at this INI section: [Settings] DBLocation=P:\USERINFO.MDB ;DBLocation=D:\CODE\TEST.MDB In the preceding section, switching from a local development database to a production database is easy. You can simply comment out the line you don't want. Using INI Files in Visual Basic One reason INI files are easy to use is that you do not have to worry about creating the file, opening the file, or finding the correct line; one function call is all it takes to save or read a value. Before you can use INI files, however, you have to declare two Windows API functions and write a couple of wrapper functions around them. We have already done this for you. Simply add the code in Listing 24.7 to the top of your form class. Tip Create your own DLL file and namespace that contains these functions, then you can reference them from any project. For more on how to do this read Chapter 9, "Creating Code Components." Listing 24.7 INIFunctions.ZIP Using INI Files in Your Program Declare Function GetPrivateProfileString Lib "kernel32" Alias _ "GetPrivateProfileStringA" (ByVal lpApplicationName _ As String, ByVal lpKeyName As String, ByVal lpDefault _ As String, ByVal lpReturnedString As String, ByVal _ nSize As Integer, ByVal lpFileName As String) As Integer Declare Function WritePrivateProfileString Lib "kernel32" Alias _ "WritePrivateProfileStringA" (ByVal lpApplicationName _ As String, ByVal lpKeyName As String, ByVal lpString As String, _ ByVal lpFileName As String) As Integer Public Shared Function sGetINI(ByVal sINIFile As String,_ ByVal sSection As String, ByVal sKey As String,_ ByVal sDefault As String) As String Dim sTemp As String = Space(255) Dim nLength As Integer nLength = GetPrivateProfileString(sSection, sKey, sDefault, sTemp, _ 255, sINIFile) Return sTemp.Substring(0, nLength) End Function Public Shared Sub writeINI(ByVal sINIFile As String,_ ByVal sSection As String, ByVal sKey As String,_ ByVal sValue As String) 'Remove CR/LF characters sValue = sValue.Replace(vbCr, vbNullChar) sValue = sValue.Replace(vbLf, vbNullChar) 'Write information to INI file WritePrivateProfileString(sSection, sKey, sValue, sINIFile) End Sub After the codein Listing 24.7 has been entered, you can use the function sGetINI and the subroutine writeINI to easily read and write to an INI file. Listing 24.8 shows how you can retrieve settings from an INI file for use at program startup. Listing 24.8 INIFunctions.ZIP Using an INI File for Program Settings Private Sub InitProgram() Dim sINIFile As String Dim sUserName As String Dim nCount As Integer Dim i As Integer 'Store the location of the INI file sINIFile = Application.StartupPath & "\..\SETTINGS.INI" 'Read the user name from the INI file sUserName = sGetINI(sINIFile, "Settings", "UserName", "?") If sUsername = "?" Then 'No user name was present - ask for it and save for next time sUserName = InputBox("Enter your name please:") writeini(sINIFile, "Settings", "UserName", sUserName) Else Me.Text = "Welcome back " & sUserName End If 'Fill up combo box list from INI file cmbRegion.Items.Clear() nCount = Convert.ToInt32(sGetINI(sINIFile, "Regions", "Count", "0")) If nCount > 0 Then For i = 0 To nCount cmbRegion.Items.Add(sGetINI(sINIFile, "Regions", "Region" & i, "?")) Next i 'select the user's last chosen item cmbRegion.SelectedIndex = Convert.ToInt32(sGetINI(sINIFile,_ "Regions", "LastRegion", "0")) End If End Sub The code in Listing 24.8 first checks the INI file for a username. By providing the default value ?, you can determine whether the username already exists in the INI file. If it doesn't exist, you can prompt for it. The default value is a great feature because it does not matter whether the INI file even exists, which makes your program less likely to throw an exception. However, if the file is important enough that you don't want your program to run without it, you display an appropriate message for the user and exit. The next part of the code example reads the number of regions from the INI file and uses that value to place each region in a combo box. The final statement sets the Text property of the combo box to a value from the INI file, using the first item in the list as a default. Driving yourprogram from INI files, as demonstrated in Listing 24.8, allows you to make minor changes to the program quickly and easily without even recompiling it. |