18.4. Classes File and Directory Information is stored in files, which are organized in directories. Classes File and Directory enable programs to manipulate files and directories on disk. Class File can determine information about files and can be used to open files for reading or writing. We discuss techniques for writing to and reading from files in subsequent sections. Figure 18.3 lists several of class File's Shared methods for manipulating and determining information about files. We demonstrate several of these methods in Fig. 18.5. Figure 18.3. File class Shared methods (partial list).File class Shared methods and descriptions |
---|
AppendText | Returns a StreamWriter that appends text to an existing file or creates a file if one does not exist. | Copy | Copies a file to a new file. | Create | Creates a file and returns its associated FileStream. | CreateText | Creates a text file and returns its associated StreamWriter. | Delete | Deletes the specified file. | Exists | Returns true if the specified file exists and False otherwise. | GetCreationTime | Returns a DateTime object representing when the file was created. | GetLastAccessTime | Returns a DateTime object representing when the file was last accessed. | GetLastWriteTime | Returns a DateTime object representing when the file was last modified. | Move | Moves the specified file to a specified location. | Open | Returns a FileStream associated with the specified file and equipped with the specified read/write permissions. | OpenRead | Returns a read-only FileStream associated with the specified file. | OpenText | Returns a StreamReader associated with the specified file. | OpenWrite | Returns a read/write FileStream associated with the specified file. |
Class Directory provides capabilities for manipulating directories. Figure 18.4 lists some of class Directory's Shared methods for directory manipulation. Figure 18.5 demonstrates several of these methods, as well. The DirectoryInfo object returned by method CreateDirectory contains information about a directory. Much of the information contained in class DirectoryInfo also can be accessed via the methods of class Directory. Figure 18.4. Directory class Shared methods.Directory class Shared methods and descriptions |
---|
CreateDirectory | Creates a directory and returns its associated DirectoryInfo object. |
---|
Delete | Deletes the specified directory. | Exists | Returns true if the specified directory exists and False otherwise. | Getdirectories | Returns a String array containing the names of the subdirectories in the specified directory. | GetFiles | Returns a String array containing the names of the files in the specified directory. | GetCreationTime | Returns a DateTime object representing when the directory was created. | GetLastAccessTime | Returns a DateTime object representing when the directory was last accessed. | GetLastWriteTime | Returns a DateTime object representing when items were last written to the directory. | Move | Moves the specified directory to a specified location. |
Figure 18.5. Testing classes File and Directory. 1 ' Fig 18.5: FrmFileTest.vb 2 ' Using classes File and Directory. 3 Imports System.IO 4 5 ' displays contents of files and directories 6 Public Class FrmFileTest 7 ' invoked when user presses key 8 Private Sub txtInput_KeyDown(ByVal sender As System.Object, _ 9 ByVal e As System.Windows.Forms.KeyEventArgs) _ 10 Handles txtInput.KeyDown 11 ' determine whether user pressed Enter key 12 If e.KeyCode = Keys.Enter Then 13 Dim fileName As String ' name of file or directory 14 15 ' get user-specified file or directory 16 fileName = txtInput.Text 17 18 ' determine whether fileName is a file 19 If File.Exists(fileName) Then 20 ' get file's creation date, 21 ' modification date, etc. 22 txtOutput.Text = GetInformation(fileName) 23 24 ' display file contents through StreamReader 25 Try 26 ' obtain reader and file contents 27 Dim stream As New StreamReader(fileName) 28 txtOutput.Text & = stream.ReadToEnd() 29 ' handle exception if StreamReader is unavailable 30 Catch ex As System.IO.IOException 31 MessageBox.Show( "Error reading from file", "File Error", _ 32 MessageBoxButtons.OK, MessageBoxIcon.Error ) 33 End Try 34 ' determine whether fileName is a directory 35 ElseIf Directory.Exists(fileName) Then 36 Dim directoryList() As String ' array for directories 37 38 ' get directory's creation date, 39 ' modification date, etc. 40 txtOutput.Text = GetInformation(fileName) 41 42 ' obtain file/directory list of specified directory 43 directoryList = Directory.GetDirectories(fileName) 44 45 txtOutput.Text & = vbCrLf & vbCrLf & _ 46 "Directory contents:" & vbCrLf 47 48 ' output directoryList contents 49 For Each directoryName As String In directoryList 50 txtOutput.Text &= directoryName & vbCrLf 51 Next 52 Else 53 ' notify user that neither file nor directory exists 54 MessageBox.Show(txtInput.Text & "does not exist", a_ 55 "File Error", MessageBoxButtons.OK, MessageBoxIcon.Error) 56 End If 57 End If 58 End Sub ' txtInput_KeyDown 59 60 ' get information on file or directory 61 Private Function GetInformation(ByVal fileName As String) As String 62 Dim information As String 63 64 ' output that file or directory exists 65 information = fileName & " exists" & vbCrLf & vbCrLf 66 67 ' output when file or directory was created 68 information &= "Created:" & _ 69 File.GetCreationTime(fileName) & vbCrLf 70 71 ' output when file or directory was last modified 72 information &= "Last modified:" & _ 73 File.GetLastWriteTime(fileName) & vbCrLf 74 75 ' output when file or directory was last accessed 76 information &= "Last accessed: " & _ 77 File.GetLastAccessTime(fileName) & vbCrLf & vbCrLf 78 79 Return information 80 End Function ' GetInformation 81 End Class ' FrmFileTest
(a)
(b)
(c)
(d) | Demonstrating Classes File and Directory Class FrmFileTest (Fig. 18.5) uses File and Directory methods to access file and directory information. This Form contains the control txtInput, in which the user enters a file or directory name. For each key that the user presses while typing in the TextBox, the program calls event handler txtInput_KeyDown (lines 858). If the user presses the Enter key (line 12), this method displays either the file's or the directory's contents, depending on the text the user input. (If the user does not press the Enter key, this method returns without displaying any content.) Line 19 uses File method Exists to determine whether the user-specified text is the name of an existing file. If so, line 22 invokes Private method GetInformation (lines 6180), which calls File methods GetCreationTime (line 69), GetLastWriteTime (line 73) and GetLastAccessTime (line 77) to access file information. When method GetInformation returns, line 27 instantiates a StreamReader for reading text from the file. The StreamReader constructor takes as an argument a String containing the name of the file to open. Line 28 calls StreamReader method ReadToEnd to read the entire contents of the file as a String, then appends the String to txtOutput. If line 19 determines that the user-specified text is not a file, line 35 determines whether it is a directory using Directory method Exists. If the user specified an existing directory, line 40 invokes method GetInformation to access the directory information. Line 43 calls Directory method Getdirectories to obtain a String array containing the names of subdirectories in the specified directory. Lines 4951 display each element in the String array. If line 35 determines that the user-specified text is not a directory name, lines 5455 notify the user (via a MessageBox) that the name the user entered does not exist as a file or directory. Finding Directories with Regular Expressions We now consider another example that uses the FCL's file- and directory-manipulation capabilities. Class FrmFileSearch (Fig. 18.6) uses classes File and Directory, and regular-expression capabilities, to report the number of files of each file type that exist in the specified directory path. The program also serves as a "clean-up" utilitywhen a file that has the .bak filename extension (i.e., a backup file) is encountered, the program displays a MessageBox asking the user whether that file should be removed, then responds appropriately to the user's input. Figure 18.6. Regular expression used to determine file types. 1 ' Fig 18.6: FrmFileSearch.vb 2 ' Using regular expressions to determine file types. 3 Imports System.IO 4 Imports System.Text.RegularExpressions 5 Imports System.Collections.Specialized 6 7 Public Class FrmFileSearch 8 Dim currentDirectory As String = Directory.GetCurrentDirectory() 9 Dim directoryList() As String ' subdirectories 10 Dim fileArray() As String 11 12 ' store extensions found and number found 13 Dim found As New NameValueCollection() 14 15 ' invoked when user types in text box 16 Private Sub txtInput_KeyDown(ByVal sender As System.Object, _ 17 ByVal e As System.Windows.Forms.KeyEventArgs) _ 18 Handles txtInput.KeyDown 19 ' determine whether user pressed Enter 20 If e.KeyCode = Keys.Enter Then 21 btnSearch_Click(sender, e) 22 End If 23 End Sub ' txtInput_KeyDown 24 25 ' invoked when user clicks "Search Directory" button 26 Private Sub btnSearch_Click(ByVal sender As System.Object, _ 27 ByVal e As System.EventArgs) Handles btnSearch.Click 28 ' check for user input; default is current directory 29 If txtInput.Text <> "" Then 30 ' verify that user input is valid directory name 31 If Directory.Exists(txtInput.Text) Then 32 currentDirectory = txtInput.Text 33 34 ' reset input text box and update display 35 lblDirectory.Text = _ 36 "Current Directory:" & vbCrLf & currentDirectory 37 Else 38 ' show error if user does not specify valid directory 39 MessageBox.Show( "Invalid Directory", "Error", _ 40 MessageBoxButtons.OK, MessageBoxIcon.Error ) 41 End If 42 End If 43 44 ' clear text boxes 45 txtInput.Text = "" 46 txtOutput.Text = "" 47 48 SearchDirectory(currentDirectory) ' search directory 49 50 ' summarize and print results 51 For Each current As String In found 52 txtOutput.Text &= "* Found " & found(current) & _ 53 " " & current & " files." & vbCrLf 54 Next current 55 56 ' clear output for new search 57 found.Clear() 58 End Sub ' btnSearch_Click 59 60 ' search directory using regular expression 61 Private Sub SearchDirectory(ByVal currentDirectory As String) 62 ' for file name without directory path 63 Try 64 Dim fileName As String = "" 65 66 ' regular expression for extensions matching pattern 67 Dim regularExpression As New Regex( _ 68 "[a-zA-Z0-9]+\.(?<extension7>\w+)") 69 70 ' stores regular-expression match result 71 Dim matchResult As Match 72 73 Dim fileExtension As String ' holds file extensions 74 75 ' number of files with given extension in directory 76 Dim extensionCount As Integer 77 78 ' get directories 79 directoryList = Directory.GetDirectories(currentDirectory) 80 81 ' get list of files in current directory 82 fileArray = Directory.GetFiles(currentDirectory) 83 84 ' iterate through list of files 85 For Each myFile As String In fileArray 86 ' remove directory path from file name 87 fileName = myFile.Substring(myFile.LastIndexOf("\" ) + 1 ) 88 89 ' obtain result for regular-expression search 90 matchResult = regularExpression.Match(fileName) 91 92 ' check for match 93 If matchResult.Success Then 94 fileExtension = matchResult.Result("${extension}" ) 95 Else 96 fileExtension = "[no extension]" 97 End If 98 99 ' store value from container 100 If found(fileExtension) Is Nothing Then 101 found.Add(fileExtension, "1") 102 Else 103 extensionCount = Int32.Parse(found(fileExtension)) + 1 104 found(fileExtension) = extensionCount.ToString() 105 End If 106 107 ' search for backup( .bak ) files 108 If fileExtension = "bak" Then 109 ' prompt user to delete ( .bak ) file 110 Dim result As DialogResult = MessageBox.Show( _ 111 "Found backup file " & fileName & ". Delete?", _ 112 "Delete Backup", MessageBoxButtons.YesNo, _ 113 MessageBoxIcon.Question) 114 115 ' delete file if user clicked 'yes' 116 If result = Windows.Forms.DialogResult.Yes Then 117 File.Delete(myFile) 118 extensionCount = Int32.Parse(found("bak")) - 1 119 found("bak") = extensionCount.ToString() 120 End If 121 End If 122 Next myFile 123 124 ' recursive call to search files in subdirectory 125 For Each myDirectory As String In directoryList 126 SearchDirectory(myDirectory) 127 Next myDirectory 128 ' handle exception if files have unauthorized access 129 Catch ex As UnauthorizedAccessException 130 MessageBox.Show( "Some files may not be visible" & _ 131 " due to permission settings", "Warning", _ 132 MessageBoxButtons.OK, MessageBoxIcon.Information) 133 End Try 134 End Sub ' SearchDirectory 135 End Class ' FrmFileSearch | When the user presses the Enter key or clicks the Search Directory button, the program invokes method btnSearch_Click (lines 2658), which searches recursively through the directory path that the user provides. If the user inputs text in the TextBox, line 31 calls Directory method Exists to determine whether that text is a valid directory path and name. If not, lines 3940 notify the user of the error. If the user specifies a valid directory, line 48 passes the directory name as an argument to Private method SearchDirectory (lines 61134). This method locates files that match the regular expression defined in lines 6768. This regular expression matches any sequence of numbers or letters followed by a period and one or more letters. Note the substring of format (?<extension>\w+) in the argument to the Regex constructor (line 68). This indicates that the part of the string that matches \w+ (i.e., the filename extension that appears after a period in the file name) should be placed in the regular-expression variable named extension. This variable's value is retrieved later from Match object matchResult to obtain the filename extension so that we can summarize the types of files in the directory. Line 79 calls Directory method Getdirectories to retrieve the names of all the subdirectories that belong to the current directory. Line 82 calls Directory method GetFiles to store in String array fileArray the names of the files in the current directory. The loop in lines 85122 searches for all files with extension .bak. The loop at lines 125127 then calls SearchDirectory recursively (line 126) for each subdirectory in the current directory. Line 87 eliminates the directory path, so the program can test only the file name when using the regular expression. Line 90 uses Regex method Match to match the regular expression with the file name, then assigns the result to Match object matchResult. If the match is successful, line 94 uses Match method Result to assign to fileExtension the value of the regular-expression variable extension from object matchResult. If the match is unsuccessful, line 96 sets fileExtension to "[no extension]". Class FrmFileSearch uses an instance of class NameValueCollection (declared in line 13) to store each filename-extension type and the number of files for each type. A NameValueCollection (namespace System.Collections.Specialized) contains a collection of key-value pairs of Strings, and provides method Add to add a key-value pair to the collection. The indexer for this class can index according to the order in which the items were added or according to the keys. Line 100 uses NameValueCollection found to determine whether this is the first occurrence of the filename extension (the expression returns Nothing if the collection does not contain a key-value pair for the specified fileExtension). If this is the first occurrence, line 101 adds that extension to found as a key with the value 1. Otherwise, line 103 increments the value associated with the extension in found to indicate another occurrence of the file extension, and line 104 assigns the new value to the key-value pair. Line 108 determines whether fileExtension equals "bak"that is, whether the file is a backup file. If so, lines 110113 prompt the user to indicate whether the file should be deleted; if the user clicks Yes (line 116), lines 117119 delete the file and decrement the value for the "bak" file type in found. Lines 125127 call method SearchDirectory for each subdirectory. Using recursion, we ensure that the program performs the same logic for finding .bak files in each subdirectory. After each subdirectory has been checked for .bak files, method SearchDirectory completes, and lines 5154 display the results. |