Visual Basic includes a bewildering assortment of objects that you can use to manipulate drives, directories, and files. The stream classes described in Chapter 36 enable you to read and write files, but they don't really capture any of the special structure of the file system.
A Visual Basic application has two main choices for working with the file system: Visual Basic methods and .NET Framework classes. This chapter describes these two approaches and the classes that they use. It finishes by describing some of the My namespace properties and methods that you can use to access file-system tools more easily. For more information on the My namespace, see the section "My" in Chapter 35, "Configuration and Resources," and Appendix S, "The My Namespace."
An application cannot perform a task if the user running it doesn't have the appropriate permissions. Although this is true of any operation a program must perform, permission issues are particularly common when working with files, and recent versions of the Windows operating system are particularly strict about enforcing permission requirements.
A common mistake is for developers to build and test an application while logged in as a user who has a lot of privileges. Sometimes, developers even have system administrator privileges, so their programs can do pretty much anything on the computer. To ensure that users will have the permissions needed by an application, develop or at least test the code using an account with the privileges that typical users will have.
Chapter 24, "UAC Security," describes permissions in greater detail.
Visual Basic provides a number of commands for manipulating the file system. These commands are relatively flexible and easy to understand. Most of them have been around since the early days of Visual Basic, so many long-time Visual Basic developers prefer to use them rather than the newer .NET Framework methods.
One disadvantage to these methods is that they do not natively allow you to read and write nonstandard data types. They can handle string, date, integer, long, single, double, and decimal data. They can also handle structures and arrays of those types. They cannot, however, handle classes themselves. You can use XML serialization to convert a class object into a string and then use these methods to read and write the result, but that requires an extra step with some added complexity.
The section "File-System Methods" later in this chapter describes the native file-system methods of Visual Basic. The sections "Sequential-File Access,""Random-File Access," and "Binary-File Access" later in this chapter describe specific issues for working with sequential, random, and binary files.
The following table describes the methods Visual Basic provides for working with files.
METHOD | PURPOSE |
---|---|
| Returns True if a file open for reading is at the end of file. (EOF stands for End Of File.) |
| Closes an open file. |
| Reads data from a file opened in Random and Binary mode into a variable. |
| Reads data as an object from a file opened in Random and Binary mode into a variable. |
| Opens a file for reading or writing. Parameters indicate the mode (Append, Binary, Input, Output, or Random), access type (Read, Write, or ReadWrite), and sharing (Shared, LockRead, LockWrite, or LockReadWrite). |
| Writes data from a variable into a file opened for Random or Binary access. |
| Writes an object from a variable into a file opened for Random or Binary access. |
| Returns a file number that is not currently associated with any file in this application. You should use FreeFile to get file numbers rather than using arbitrary numbers such as 1. |
| Reads data written into a file by the Write method back into a variable. |
| Reads a specific number of characters from the file. |
| Returns the next line of text from the file. |
| Returns the current position within the file. |
| Returns the file's length in bytes. ("LOF" stands for Length Of File.) |
| Prints values into the file. Multiple values separated by commas are aligned at tab boundaries. |
| Prints values followed by a new line into the file. Multiple values separated by commas are aligned at tab boundaries. |
| Moves to the indicated position within the file. |
| Writes values into the file, delimited appropriately so that they can later be read by the Input method. |
| Writes values followed by a new line into the file, delimited appropriately so that they can later be read by the Input method. |
Many of the Visual Basic file methods use a file number to represent an open file. The file number is just a number used to identify the file. There's nothing magic about it. You just need to be sure not to use the same file number for more than one file at a time. The FreeFile method returns a number that is not in use so that you know it is safe to use as a file number.
The following example uses FreeFile to get an available file number. It uses FileOpen to open a file for reading. Then, while the EOF method indicates that the code hasn't reached the end of the file, the program uses LineInput to read a line from the file and it displays the line. When it finishes reading the file, the program uses FileClose to close it.
' Get an available file number. Dim file_num As Integer = FreeFile() ' Open the file. FileOpen(file_num, "C:Temp est.txt", OpenMode.Input, OpenAccess.Read, OpenShare.Shared) ' Read the file's lines. Do While Not EOF(file_num) ' Read a line. Dim txt As String = LineInput(file_num) Debug.WriteLine(txt) Loop ' Close the file. FileClose(file_num)
Visual Basic also provides several methods for working with the file system. The following table describes methods that manipulate directories and files.
METHOD | PURPOSE |
---|---|
| Changes the application's current working directory. |
| Changes the application's current working drive. |
| Returns the application's current working directory. |
| Returns a file matching a directory path specification that may include wildcards, and matching certain file properties such as ReadOnly, Hidden, or Directory. The first call to Dir should include a path. Subsequent calls can omit the path to fetch the next matching file for the initial path. Dir returns file names without the path and returns Nothing when no more files match. |
| Copies a file to a new location. |
| Returns the date and time when the file was created or last modified. |
| Returns the length of a file in bytes. |
| Returns a value indicating the file's attributes. The value is a combination of the values vbNormal, vbReadOnly, vbHidden, vbSystem, vbDirectory, vbArchive, and vbAlias. |
| Permanently deletes a file. |
| Creates a new directory. |
| Renames a directory or file. |
| Deletes an empty directory. |
| Sets the file's attributes. The attribute value is a combination of the values vbNormal, vbReadOnly, vbHidden, vbSystem, vbDirectory, vbArchive, and vbAlias. |
With sequential file access, a program reads or writes the contents of a file byte-by-byte from start to finish with no jumping around. In contrast, in a random-access file, the program can jump freely to any position in the file and write data wherever it likes.
A text file is a typical sequential file. The program can read the text in order, and read it one line at a time, but it cannot easily jump around within the file.
The Input, InputString, LineInput, Print, PrintLine, Write, and WriteLine methods provide sequential access to files.
The Print and PrintLine methods provide mostly unformatted results. If you pass these methods multiple parameters separated by commas, they align the results on tab boundaries. Write and WriteLine, on the other hand, delimit their output so that it can be easily read by the Input method.
A program cannot directly modify only part of a sequential file. For example, it cannot modify, add, or remove a sentence in the middle of a paragraph. If you must modify the file, you should read it into a string, make the changes you want, and then rewrite the file.
If you must frequently modify text in the middle of a file, you should consider using random or binary access, or storing the data in a database.
A random-access file contains a series of fixed-length records. For example, you could create an employee file that contains a series of values defining an employee. Each record would have fixed-length fields to hold an employee's ID, first name, last name, street address, and so forth, as shown in the following structure definition:
Structure Employee Public Id As Long <VBFixedString(20) > Public FirstName As String <VBFixedString(20) > Public LastName As String <VBFixedString(40) > Public Street As String ... End Structure
When you open a file for random access, you can jump to any record in the file. That makes certain kinds of file manipulation easier. For example, if the file is sorted, you can use a binary search to locate records in it.
You can overwrite the values in a record within the file, but you cannot add or remove records in the middle of the file. If you must make those sorts of changes, you must load the file into memory and then rewrite it from scratch.
The FileGet, FileGetObject, FilePut, and FilePutObject methods read and write records in random-access files. Example program RandomAccessEmployees uses the following code to demonstrate the FilePut and FileGet methods:
Public Class Form1 Public Structure Employee Public ID As Integer <VBFixedString(15) > Public FirstName As String <VBFixedString(15) > Public LastName As String Public Sub New(ByVal new_id As Integer, ByVal first_name As String, ByVal last_name As String) ID = new_id FirstName = first_name LastName = last_name End Sub Public Overrides Function ToString() As String Return ID & ": " & FirstName & " " & LastName End Function End Structure Private Sub btnMakeRecords_Click() Handles btnMakeRecords.Click ' Declare a record variable. Dim emp As New Employee ' Get an available file number. Dim file_num As Integer = FreeFile() ' Open the file. FileOpen(file_num, "MYFILE.DAT", OpenMode.Random, OpenAccess.ReadWrite, OpenShare.Shared, Len(emp)) ' Make some records. FilePut(file_num, New Employee(1, "Alice", "Altanta")) FilePut(file_num, New Employee(2, "Bob", "Bakersfield")) FilePut(file_num, New Employee(3, "Cindy", "Chicago")) FilePut(file_num, New Employee(4, "Dan", "Denver")) FilePut(file_num, New Employee(5, "Erma", "Eagle")) FilePut(file_num, New Employee(6, "Fred", "Frisco")) ' Fetch and display the records. Dim obj As ValueType = DirectCast(emp, ValueType) For Each i As Integer In New Integer() {3, 1, 5, 2, 6} FileGet(file_num, obj, i) emp = DirectCast(obj, Employee) Debug.WriteLine("[" & emp.ToString() & "]") Next i ' Close the file. FileClose(file_num) End Sub End Class
First, the code defines a structure named Employee to hold the data in a record. Notice how the code uses the VBFixedString
attribute to flag the strings as fixed length. The structure must have a fixed length if you want to jump randomly through the file because Visual Basic calculates a record's position by multiplying a record's size by its index in the file. If records contained strings of unknown length, the calculation wouldn't work.
When the user clicks the Make Records button, the btnMakeRecords_Click event handler executes. This code declares a variable of the record type, Employee. It uses the FreeFile method to get an available file number and uses FileOpen to open the file for random access. The final parameter to FileOpen is the length of the file's records. To calculate this length, the program uses the Len function, passing it the Employee instance emp.
Next, the program uses the FilePut method to write six records into the file. It passes FilePut the file number and a new Employee structure. The structure's constructor makes initializing the new records easy.
The program then uses FileGet to retrieve the six records using their indexes as keys, fetching them out of numeric order to demonstrate random access. It then displays each record's data in the Output window surrounded by brackets so you can see where the data starts and ends.
There are two key points to notice here. First, the file numbers records starting with 1 not 0, so the first record in the file has index 1.
Second, the FileGet method does not have an overloaded version that takes an Employee structure as a parameter. Because this example has Option Strict set to On, the code must perform some shenanigans to pass FileGet a ValueType variable and then later convert it into an Employee.
If you set Option Strict to Off, you can pass an Employee object directly into FileGet. Turning off Option Strict is generally a bad idea, however, because it can hide implicit data type conversions that may indicate a mistake. You can minimize the danger by placing as little code as possible in the file with Option Strict Off. For example, if the code that uses FileGet is in a class, you can use the Partial keyword to move that code into a separate module. Then that module can turn off Option Strict whereas the rest of the class's code keeps Option Strict On.
After it has read and displayed the records, the program uses FileClose to close the file.
The following text shows the result. Notice that the first and last names are padded with spaces to 15 characters, the length of the Employee structure's fixed-length strings. The last names are also padded to 15 characters.
[3: Cindy Chicago ] [1: Alice Altanta ] [5: Erma Eagle ] [2: Bob Bakersfield ] [6: Fred Frisco ]
Binary access is similar to random access, except that it does not require its data to fit into neat records. You get control over pretty much every byte in the file, and you can jump to an arbitrary byte number in the file. If the items in the file are not fixed-length records, however, you cannot jump to a particular record because you cannot calculate where that record would begin.
The System.IO namespace provides several classes for working with the file system. The Directory and File classes provide shared methods that you can use to manipulate the file system without creating instances of helper objects.
The DirectoryInfo and FileInfo classes let you work with specific relevant file system objects. For example, a FileInfo object represents a particular file and provides methods to create, rename, delete, and get information about that file.
The following sections describe these and the other classes that the Framework provides to help you work with the file system.
The Directory class provides shared methods for working with directories. These methods let you create, rename, move, and delete directories. They let you enumerate the files and subdirectories within a directory, and get and set directory information such as the directory's creation and last access time.
The following table describes the Directory class's shared methods.
METHOD | PURPOSE |
---|---|
| Creates a directory and any missing ancestors (parent, grandparent, and so on). |
| Deletes a directory and its contents. It can delete all subdirectories, their subdirectories, and so forth to remove the entire directory tree. |
| Returns True if the path points to an existing directory. |
| Returns a directory's creation date and time. |
| Returns a directory's creation date and time in Coordinated Universal Time (UTC). |
| Returns the application's current working directory. |
| Returns an array of strings holding the fully qualified names of a directory's subdirectories. |
The File class provides shared methods for working with files. These methods let you create, rename, move, and delete files. They also make working with file streams a bit easier.
The following table describes the File class's most useful shared methods.
METHOD | PURPOSE |
---|---|
| Adds text to the end of a file, creating it if it doesn't exist, and then closes the file. |
| Opens a file for appending UTF-8 encoded text and returns a StreamWriter class attached to it. |
| Copies a file. |
| Creates a new file and returns a FileStream attached to it. |
| Creates or opens a file for writing UTF-8 encoded text and returns a StreamWriter class attached to it. |
| Permanently deletes a file. |
| Returns True if the specified file exists. |
| Gets a file's attributes. This is a combination of flags defined by the FileAttributes enumeration: Archive, Compressed, Device, Directory, Encrypted, Hidden, Normal, NotContextIndexed, Offline, ReadOnly, ReparsePoint, SparseFile, System, and Temporary. |
| Returns a file's creation date and time. |
| Returns a file's creation date and time in UTC. |
| Returns a file's last access date and time. |
| Returns a file's last access date and time in UTC. |
| Returns a file's last write date and time. |
| Returns a file's last write date and time in UTC. |
| Moves a file to a new location. |
| Opens a file and returns a FileStream attached to it. Parameters let you specify the mode (Append, Create, CreateNew, Open, OpenOrCreate, or Truncate), access (Read, Write, or ReadWrite), and sharing (Read, Write, ReadWrite, or None) settings. |
| Opens a file for reading and returns a FileStream attached to it. |
| Opens a UTF-8-encoded text file for reading and returns a StreamReader attached to it. |
| Opens a file for writing and returns a FileStream attached to it. |
| Returns a file's contents in an array of bytes. |
| Returns a file's lines in an array of strings. |
| Returns a file's contents in a string. |
| Takes three file paths as parameters, representing a source file, a destination file, and a backup file. If the backup file exists, this method permanently deletes it. It then moves the destination file to the backup file, and moves the source file to the destination file. For example, imagine a program that writes a log file every time it runs. It could use this method to keep three versions of the log: the current log (the method's source file), the most recent backup (the method's destination file), and a second backup (the method's backup file). This method throws an error if either the source or destination file doesn't exist. |
| Sets a file's attributes. This is a combination of flags defined by the FileAttributes enumeration: Archive, Compressed, Device, Directory, Encrypted, Hidden, Normal, NotContextIndexed, Offline, ReadOnly, ReparsePoint, SparseFile, System, and Temporary. |
| Sets a file's creation date and time. |
| Sets a file's creation date and time in UTC. |
| Sets a file's last access date and time. |
| Sets a file's last access date and time in UTC. |
| Sets a file's last write date and time. |
| Sets a file's last write date and time in UTC. |
| Creates or replaces a file, writes an array of bytes into it, and closes the file. |
| Creates or replaces a file, writes an array of strings into it, and closes the file. |
| Creates or replaces a file, writes a string into it, and closes the file. |
A DriveInfo object represents one of the computer's drives. The following table describes the properties provided by this class. Note that some of these properties are available only when the drive is ready, as indicated in the Must Be Ready column. If you try to access them when the drive is not ready, Visual Basic throws an exception. The program should check the IsReady property to determine whether the drive is ready before trying to use the AvailableFreeSpace, DriveFormat, TotalFreeSpace, or VolumeLabel properties.
DRIVEINFO PROPERTY | PURPOSE | MUST BE READY |
---|---|---|
| Returns the amount of free space available on the drive in bytes. | True |
| Returns the name of the file-system type such as NTFS (NT File System) or FAT32 (32-bit File Allocation Table). (For a comparison of these, see | True |
| Returns a DriveType enumeration value indicating the drive type. This value can be CDRom, Fixed, Network, NoRootDirectory, Ram, Removable, or Unknown. | False |
| Returns True if the drive is ready. Many DriveInfo properties are unavailable and raise exceptions if you try to access them while the drive is not ready. | False |
| Return's the drive's name. This is the drive's root name (as in A: or C:). | |
| Returns a DirectoryInfo object representing the drive's root directory. See the following section "DirectoryInfo" for more information on this class. | False |
| Returns the total amount of free space on the drive in bytes. | True |
| Gets or sets the drive's volume label. | True |
The DriveInfo class also has a public shared method GetDrives that returns an array of DriveInfo objects describing the system's drives.
A DirectoryInfo object represents a directory. You can use its properties and methods to create and delete directories and to move through a directory hierarchy.
The following table describes the most useful public properties and methods provided by the DirectoryInfo class.
PROPERTY OR METHOD | PURPOSE |
---|---|
| Gets or sets flags for the directory from the FileAttributes enumeration: Archive, Compressed, Device, Directory, Encrypted, Hidden, Normal, NotContentIndexed, Offline, ReadOnly, ReparsePoint, SparseFile, System, and Temporary. |
| Creates the directory. You can create a DirectoryInfo object, passing its constructor the fully qualified name of a directory that doesn't exist. You can then call the object's Create method to create the directory. |
| Creates a subdirectory within the directory and returns a DirectoryInfo object representing it. The subdirectory's path must be relative to the DirectoryInfo object's directory, but can contain intermediate subdirectories. For example, the following code creates the Tools subdirectory and the Bin directory inside that: |
| Gets or sets the directory's creation time. |
| Gets or sets the directory's creation time in UTC. |
| Deletes the directory if it is empty. A parameter lets you tell the object to delete its contents, too, if it isn't empty. |
| Returns True if the directory exists. |
| Returns the extension part of the directory's name. Normally, this is an empty string for directories. |
| Returns the directory's fully qualified path. |
| Returns an array of DirectoryInfo objects representing the directory's subdirectories. An optional parameter gives a pattern to match. This method does not recursively search the subdirectories. |
| Returns an array of FileInfo objects representing files inside the directory. An optional parameter gives a pattern to match. This method does not recursively search subdirectories. |
| Returns a strongly typed array of FileSystemInfo objects, representing subdirectories and files inside the directory. The items in the array are DirectoryInfo and FileInfo objects, both of which inherit from FileSystemInfo. An optional parameter gives a pattern to match. This method does not recursively search subdirectories. |
| Gets or sets the directory's last access time. |
| Gets or sets the directory's last access time in UTC. |
| Gets or sets the directory's last write time. |
| Gets or sets directory's last write time in UTC. |
| Moves the directory and its contents to a new path. |
| The directory's name without the path information. |
| Returns a DirectoryInfo object, representing the directory's parent. If the directory is its file system's root (for example, C:), this returns Nothing. |
| Refreshes the DirectoryInfo object's data. For example, if the directory has been accessed since the object was created, you must call Refresh to load the new LastAccessTime value. |
| Returns a DirectoryInfo object representing the root of the directory's file system. |
| Returns the directory's fully qualified path and name. |
A FileInfo object represents a file. You can use its properties and methods to create and delete directories and to move through a directory hierarchy.
The following table describes the most useful public properties and methods provided by the FileInfo class.
PROPERTY OR METHOD | PURPOSE |
---|---|
| Returns a StreamWriter that appends text to the file. |
| Gets or sets flags for the file from the FileAttributes enumeration: Archive, Compressed, Device, Directory, Encrypted, Hidden, Normal, NotContentIndexed, Offline, ReadOnly, ReparsePoint, SparseFile, System, and Temporary. |
| Copies the file and returns a FileInfo object, representing the new file. A parameter lets you indicate whether the copy should overwrite an existing file. If the destination path is relative, it is relative to the application's current directory, not to the FileInfo object's directory. |
| Creates the file and returns a FileStream object attached to it. For example, you can create a FileInfo object, passing its constructor the name of a file that doesn't exist. Then you can call the Create method to create the file. |
| Creates the file and returns a StreamWriter attached to it. For example, you can create a FileInfo object passing its constructor the name of a file that doesn't exist. Then you can call the CreateText method to create the file. |
| Gets or sets the file's creation time. |
| Gets or sets the file's creation time in UTC. |
| Deletes the file. |
| Returns a DirectoryInfo object representing the file's directory. |
| Returns the name of the file's directory. |
| Returns True if the file exists. |
| Returns the extension part of the file's name, including the period. For example, the extension for game.txt is .txt. |
| Returns the file's fully qualified path and name. |
| Returns True if the file is marked read-only. |
| Gets or sets the file's last access time. |
| Gets or sets the file's last access time in UTC. |
| Gets or sets the file's last write time. |
| Gets or sets the file's last write time in UTC. |
| Returns the number of bytes in the file. |
| Moves the file to a new location. If the destination uses a relative path, it is relative to the application's current directory, not to the FileInfo object's directory. When this method finishes, the FileInfo object is updated to refer to the file's new location. |
| The file's name without the path information. |
Opens the file with various mode (Append, Create, CreateNew, Open, OpenOrCreate, or Truncate), access (Read, Write, or ReadWrite), and sharing (Read, Write, ReadWrite, or None) settings. This method returns a FileStream object attached to the file. | |
| Returns a read-only FileStream attached to the file. |
| Returns a StreamReader with UTF-8 encoding attached to the file for reading. |
| Returns a write-only FileStream attached to the file. |
| Refreshes the FileInfo object's data. For example, if the file has been accessed since the object was created, you must call Refresh to load the new LastAccessTime value. |
| Replaces a target file with this one, renaming the old target as a backup copy. If the backup file already exists, it is deleted and replaced with the target. You can use this method to save backups of logs and other periodically updated files. |
| Returns the file's fully qualified name. |
The FileSystemInfo class is the parent class for the FileInfo and DirectoryInfo classes. It is a MustInherit class, so you cannot create instances of it directly, but some routines return this class rather than the more specific child classes. For example, the DirectoryInfo class's GetFileSystemInfos method returns an array of FileSystemInfo objects describing the files in the directory.
The FileSystemWatcher class keeps an eye on part of the file system and raises events to let your program know if something changes. For example, you could make a FileSystemWatcher monitor a work directory. When a new file with a .job extension arrives, the watcher could raise an event and your application could process the file.
The FileSystemWatcher class's constructor takes parameters that tell it which directory to watch and that give it a filter for selecting files to watch. For example, the filter might be "*.txt" to watch for changes to text files. The default filter is "*.*", which catches changes to all files that have an extension. Set the filter to the empty string "" to catch changes to all files including those without extensions.
The following table describes the FileSystemWatcher class's most useful properties.
PROPERTY | PURPOSE |
---|---|
| Determines whether the component is enabled. Note that this property is False by default, so the watcher will not raise any events until you set it to True. |
| Determines the files for which the watcher reports events. You cannot watch for multiple file types as in *.txt and *.dat. Instead use multiple FileSystemWatcher classes. If you like, you can use AddHandler to make all of the FileSystemWatcher classes use the same event handlers. |
| Determines whether the object watches subdirectories within the main path. |
| Determines the size of the internal buffer. If the watcher is monitoring a very active directory, a small buffer may overflow. |
| Determines the types of changes that the watcher reports. This is a combination of values defined by the NotifyFilters enumeration and can include the values Attributes, CreationTime, DirectoryName, FileName, LastAccess, LastWrite, Security, and Size. |
| Determines the path to watch. |
The FileSystemWatcher class provides only two really useful methods. First, Dispose releases resources used by the component. When you are finished using a watcher, call its Dispose method to allow garbage collection to reclaim its resources more efficiently.
Second, the WaitForChanged method waits for a change synchronously (with an optional timeout). When a change occurs, the method returns a WaitForChangedResult object, giving information about the change that occurred.
When the FileSystemWatcher detects a change asynchronously, it raises an event to let the program know what has happened. The following table describes the class's events.
NAME | DESCRIPTION |
---|---|
| A file or subdirectory has changed. |
| A file or subdirectory was created. |
| A file or subdirectory was deleted. |
| The watcher's internal buffer overflowed. |
| A file or subdirectory was renamed. |
The following simple example shows how to use a FileSystemWatcher to look for new files in a directory:
Private WithEvents fswJobFiles As FileSystemWatcher Private Sub Form1_Load() Handles MyBase.Load Dim watch_path As String = FileSystem.GetParentPath(Application.StartupPath) fswJobFiles = New FileSystemWatcher(watch_path, "*.job") fswJobFiles.NotifyFilter = NotifyFilters.FileName fswJobFiles.EnableRaisingEvents = True End Sub Private Sub fswJobFiles_Created(ByVal sender As Object, ByVal e As System.IO.FileSystemEventArgs) Handles fswJobFiles.Created ' Process the new file. MessageBox.Show("Process new job: " & e.FullPath) File.Delete(e.FullPath) End Sub
The program uses the WithEvents keyword to declare a FileSystemWatcher object. When the program's main form loads, the Form1_Load event handler allocates this object. Its constructor sets the object's path to the program's startup directory's parent. It sets the object's filter to "*.job" so that the object will watch for changes to files that end with a .job extension.
The event handler sets the watcher's NotifyFilter to FileName, so it will raise its Created event if a new file name appears in the target directory. Unfortunately, the NotifyFilter values (Attributes, CreationTime, DirectoryName, FileName, LastAccess, LastWrite, Security, and Size) do not match up well with the events provided by the FileSystemWatcher, so you need to figure out which NotifyFilter values to set to raise different kinds of events.
The Form1_Load event handler finishes by setting the watcher's EnableRaisingEvents property to True so the object starts watching.
When a .job file is created in the watcher's target directory, the program's fswJobFiles_Created executes. The program processes and then deletes the file. In this example, the program processes the file by displaying a message giving its fully qualified name. A more realistic example might read the file; parse fields, indicating the type of job this is; assign it to an employee for handling; and then e-mail it to that employee.
The UseFileSystemWatcher example program, which is available for download on the book's web site, uses similar code without the filter to look for any new file in the program's startup directory.
The Path class provides shared properties and methods that you can use to manipulate paths. Its methods return the path's file name, extension, directory name, and so forth. Other methods provide values that do not relate to a specific path. For example, they can give you the system's temporary directory path, or the name of a temporary file.
The following table describes the Path class's most useful public properties.
PROPERTY | PURPOSE |
---|---|
| Returns the alternate character used to separate directory levels in a hierarchical path. Typically this is /. |
| Returns the character used to separate directory levels in a hierarchical path. Typically this is (as in |
| Returns a character array that holds characters that are not allowed in a path string. Typically, this array includes characters such as ", <, >, and |, as well as nonprintable characters such as those with ASCII values between 0 and 31. |
| Returns the character used to separate path strings in environment variables. Typically this is a semi-colon (;). |
| Returns the character placed between a volume letter and the rest of the path. Typically this is a colon (:). |
The following table describes the Path class's most useful methods.
METHOD | PURPOSE |
---|---|
| Changes a path's extension. |
| Returns two path strings concatenated. |
| Returns a path's directory. |
| Returns a path's extension. |
| Returns a path's file name and extension. |
| Returns a path's file name without the extension. |
| Returns a path's fully qualified value. This can be particularly useful for converting a partially relative path into an absolute path. For example, the following statement returns the string |
| Returns an array listing characters that are invalid in file names. |
| Returns an array listing characters that are invalid in file paths. |
| Returns a path's root directory string. For example, the following statement returns the string |
| Returns a random file name. |
| Creates a uniquely named, empty temporary file and returns its fully qualified path. Your program can open that file for scratch space, do whatever it needs to do, close the file, and then delete it. A typical file name might be |
| Returns the path to the system's temporary folder. This is the path part of the file names returned by GetTempFileName. |
| Returns True if a path includes an extension. |
| Returns True if a path is an absolute path. This includes |
The My.Computer.FileSystem object provides tools for working with drives, directories, and files. The following table summarizes this object's properties.
PROPERTY | DESCRIPTION |
---|---|
| Gets or sets the fully qualified path to the application's current directory. |
| Returns a read-only collection of DriveInfo objects describing the system's drives. See the section "DriveInfo" earlier in this chapter for information about the DriveInfo class. |
| Returns a SpecialDirectoriesProxy object that has properties giving the locations of various special directories (such as the system's temporary directory and the user's MyDocuments directory). See the following section "My.Computer.FileSystem.SpecialDirectories" for more information. |
The following list describes the My.Computer.FileSystem object's methods:
METHOD | PURPOSE |
---|---|
| Combines a base path with a relative path reference and returns a properly formatted fully qualified path. For example, the following code displays the name of the directory that is the parent of the application's current directory:
MessageBox.Show(My.Computer.FileSystem.CombinePath (My.Computer.FileSystem.CurrentDirectory(), ".") |
| Copies a directory. Parameters indicate whether to overwrite existing files, whether to display a progress indicator, and what to do if the user presses Cancel during the operation. |
| Copies a file. Parameters indicate whether to overwrite existing files, whether to display a progress indicator, and what to do if the user presses Cancel during the operation. |
| Creates a directory. This method will create ancestor directories if necessary. For example, if the C:Temp directory contains no subdirectories, creating C:TempProjectData will automatically create C:TempProject and C:TempProjectData. |
| Deletes a directory. Parameters indicate whether to recursively delete subdirectories, prompt the user for confirmation, or move the directory into the Recycle Bin. |
| Deletes a file. Parameters indicate whether to prompt the user for confirmation or move the file into the Recycle Bin, and what to do if the user presses Cancel while the deletion is in progress. |
| Returns True if a specified directory exists. |
| Returns True if a specified file exists. |
| Returns a read-only collection of strings listing files that contain a target string. |
| Returns a string collection listing subdirectories of a given directory. Parameters tell whether to recursively search the subdirectories, and the wildcards to match. |
| Returns a DirectoryInfo object for a directory. See the section "DirectoryInfo" earlier in this chapter for more information. |
| Returns a DriveInfo object for a drive. See the section "DriveInfo" earlier in this chapter for more information. |
| Returns a FileInfo object for a file. See the section "FileInfo" earlier in this chapter for more information. |
| Returns a string collection holding the names of files within a directory. Parameters indicate whether the search should recursively search subdirectories, and give wildcards to match. |
| Returns the fully qualified path of a path's parent. For example, this returns a file's or directory's parent directory. |
| Moves a directory. Parameters indicate whether to overwrite files that have the same name in the destination directory and whether to prompt the user when such a collision occurs. |
| Moves a file. Parameters indicate whether to overwrite a file that has the same name as the file's destination and whether to prompt the user when such a collision occurs. |
| Opens a TextFieldParser object attached to a delimited or fixed-field file such as a log file. You can use the object to parse the file. |
| Opens a StreamReader object attached to a file. You can use the object to read the file. |
| Opens a StreamReader object attached to a file. You can use the object to write into the file. |
| Reads all of the bytes from a binary file into an array. |
| Reads all of the text from a text file into a string. |
| Renames a directory within its parent directory. |
| Renames a file with its directory. |
| Writes an array of bytes into a binary file. A parameter tells whether to append the data or rewrite the file. |
| Writes a string into a text file. A parameter tells whether to append the string or rewrite the file. |
The My.Computer.FileSystem.SpecialDirectories property returns a SpecialDirectoriesProxy object that has properties giving the locations of various special directories such as the system's temporary directory and the user's MyDocuments directory.
The following table describes these special directory properties.
PROPERTY | PURPOSE |
---|---|
| Application settings for all users. |
| Application settings for the current user. |
| The current user's desktop directory. |
| The current user's MyDocuments directory. |
| The current user's MyMusic directory. |
| The current user's MyPictures directory. |
| The current user's Start MenuPrograms directory. |
| The current user's Start MenuPrograms directory. |
| The current user's temporary directory. |
Visual Basic provides a native set of methods for reading and writing files, including FreeFile, FileOpen, Input, LineInput, Print, Write, and FileClose. It also provides method for working with the file system (such as ChDir, MkDir, Kill, and RmDir). If you have a lot of previous experience with Visual Basic, you may prefer these familiar methods.
The System.IO namespace offers many objects that provide even more powerful capabilities than the native methods of Visual Basic. Classes such as Directory, DirectoryInfo, File, and FileInfo make it easy to create, examine, move, rename, and delete directories and files. The File class's methods make it particularly easy to read or write an entire file and to create streams attached to files for reading or writing.
The FileSystemWatcher class lets an application keep an eye on a file or directory and take action when it is changed. For example, a program can watch a spooling directory and take action when a new file appears in it.
The Path class provides miscellaneous support for working with paths. For example, it provides methods for examining a path's file name or extension.
The My.Computer.FileSystem namespace provides shortcuts to some of the more useful of the methods offered by the other file system classes. Its methods let you create, examine, and delete files and directories. The SpecialDirectories object also provides information about the locations of system directories.
There is considerable overlap among all of these tools, so you don't need to feel that you have to use them all. Take a good look so you know what's there, and then pick the tools that you find the most comfortable.
The tools that this chapter describes allow you fairly unstructured access to files. These classes and methods let you do just about anything you want to a file. That flexibility, however, means that you must know exactly what you want to do to the file. By letting you do anything, these tools make you do everything.
One of the most important ways an application can interact with the computer that is running it is through the file system. The classes and methods that this chapter describes allow an application to interact with the local computer's file system relatively easily.
Interacting with other computers is much more complicated. Chapter 38, "Windows Communication Foundation," describes tools that the .NET Framework provides to make interacting with remote computers easier.