What’s in This Chapter
Directory
and File
classesDriveInfo
, DirectoryInfo
, and FileInfo
classesFileSystemWatcher
and Path
classesWrox.com Downloads for This Chapter
Please note that all the code examples for this chapter are available as a part of this chapter’s code download on the book’s website at www.wrox.com/go/csharp5programmersref on the Download Code tab.
The preceding chapter described stream classes that you can use to read and write files. (It also described the File
class, which isn’t a stream class but is just too useful to ignore when you use streams.) Those classes are handy but even those like StreamWriter
that work at the highest levels still represent only the contents of files. They don’t give you any tools for working with the filesystem. Some of their methods can create a file, but they cannot rename or delete a file, or create or delete a directory.
This chapter describes classes that represent the filesystem. They allow you to create, rename, and delete files and directories. The final section in this chapter explains another important file-managing topic: how to use the recycle bin (wastebasket).
A program cannot perform a task unless the user has the appropriate permissions. Although this is true of every application, it’s a particular issue for those that work with files. Users need the appropriate permissions to read, write, create, and delete files and directories.
A common mistake is for developers to build and test an application from an account that has a lot of privileges. The program runs fine from the developer’s account, but normal users can’t use it because they don’t have the necessary privileges.
To ensure that users can use a program, you should always test it from an account that has typical user privileges.
The System.IO
namespace provides several classes for working with the filesystem. The DirectoryInfo
and FileInfo
classes let you work with specific filesystem objects. For example, a FileInfo
object represents a particular file and provides methods to create, rename, delete, and get information about that file.
The Directory
and File
classes provide static methods that you can use to manipulate the filesystem without creating instances of helper objects. For example, the Directory
class’s Delete
method lets you delete a directory without creating a DirectoryInfo
object associated with the directory.
The following sections describe these and the other classes that the .NET Framework provides to help you work with the filesystem.
The Directory
class provides static methods for working with directories. These methods let you create, rename, move, and delete directories. They also 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 times.
The following table describes the Directory
class’s static methods.
Method | Purpose |
CreateDirectory | Creates a directory. This method creates ancestor directories if necessary. |
Delete | Deletes a directory and its contents. This method can remove the entire directory tree. |
Exists | Returns true if a path points to an existing directory. |
GetCreationTime | Returns a directory’s creation date and time. |
GetCreationTimeUtc | Returns a directory’s creation date and time in Coordinated Universal Time (UTC). |
GetCurrentDirectory | Returns the application’s current working directory. |
GetDirectories | Returns an array of strings holding the fully qualified names of a directory’s subdirectories. |
GetDirectoryRoot | Returns the directory root for a path, for example, C: . |
GetFiles | Returns an array of strings holding the fully qualified names of a directory’s files. Optionally, you can search for files that match a pattern and you can search subdirectories. |
GetFileSystemEntries | Returns an array of strings holding the fully qualified names of a directory’s files and subdirectories. Optionally, you can search for files and directories that match a pattern and you can search subdirectories. |
GetLastAccessTime | Returns a directory’s last access date and time. |
GetLastAccessTimeUtc | Returns a directory’s last access date and time in UTC. |
GetLastWriteTime | Returns the date and time when a directory was last modified. |
GetLastWriteTimeUtc | Returns the date and time in UTC when a directory was last modified. |
GetLogicalDrives | Returns an array of strings listing the system’s logical drives as in A: . The list includes only drives that are attached. For example, it lists an empty floppy drive and a connected flash drive but doesn’t list a flash drive after you disconnect it. |
GetParent | Returns a DirectoryInfo object representing a directory’s parent. |
Move | Moves a directory and its contents to a new location on the same disk volume. |
SetCreationTime | Sets a directory’s creation date and time. |
SetCreationTimeUtc | Sets a directory’s creation date and time in UTC. |
SetCurrentDirectory | Sets the application’s current working directory. |
SetLastAccessTime | Sets a directory’s last access date and time. |
SetLastAccessTimeUtc | Sets a directory’s last access date and time in UTC. |
SetLastWriteTime | Sets a directory’s last write date and time. |
SetLastWriteTimeUtc | Sets a directory’s last write date and time in UTC. |
The preceding chapter mentioned the File
class and specifically its Exists
method. This class provides many other static 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 static methods.
Method | Purpose |
AppendAllLines | Adds text to the end of a file, creating it if it doesn’t exist. |
AppendText | Opens a file for appending UTF-8 encoded text and returns a StreamWriter object attached to it. |
Copy | Copies a file. |
Create | Creates a new file and returns a FileStream attached to it. |
CreateText | Creates or opens a file for writing UTF-8 encoded text and returns a StreamWriter object attached to it. |
Delete | Permanently deletes a file. |
Exists | Returns true if the specified file exists. |
GetAttributes | Gets a file’s attributes. This is a combination of FileAttributes flags that can include Archive , Compressed , Device , Directory , Encrypted , IntegrityStream , Hidden , Normal , NoScrubData , NotContextIndexed , Offline , ReadOnly , ReparsePoint , SparseFile , System , and Temporary . |
GetCreationTime | Returns a file’s creation date and time. |
GetCreationTimeUtc | Returns a file’s creation date and time in UTC. |
GetLastAccessTime | Returns a file’s last access date and time. |
GetLastAccessTimeUtc | Returns a file’s last access date and time in UTC. |
GetLastWriteTime | Returns a file’s last write date and time. |
GetLastWriteTimeUtc | Returns a file’s last write date and time in UTC. |
Move | Moves a file to a new location. |
Open | 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. |
OpenRead | Opens a file for reading and returns a FileStream attached to it. |
OpenText | Opens a UTF-8-encoded text file for reading and returns a StreamReader attached to it. |
OpenWrite | Opens a file for writing and returns a FileStream attached to it. |
ReadAllBytes | Returns a file’s contents in an array of bytes. |
ReadAllLines | Returns a file’s lines in an array of strings. |
ReadAllText | Returns a file’s contents in a string. |
Replace | 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. |
SetAttributes | Sets a file’s attributes. This is a combination of flags defined by the FileAttributes enumeration. (See the GetAttributes method’s entry for the possible values.) |
SetCreationTime | Sets a file’s creation date and time. |
SetCreationTimeUtc | Sets a file’s creation date and time in UTC. |
SetLastAccessTime | Sets a file’s last access date and time. |
SetLastAccessTimeUtc | Sets a file’s last access date and time in UTC. |
SetLastWriteTime | Sets a file’s last write date and time. |
SetLastWriteTimeUtc | Sets a file’s last write date and time in UTC. |
WriteAllBytes | Creates or replaces a file, writes an array of bytes into it, and closes the file. |
WriteAllLines | Creates or replaces a file, writes an array of strings into it, and closes the file. |
WriteAllText | 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 following table’s Must Be Ready column. If you try to access them when the drive is not ready, C# throws an exception.
Property | Purpose | Must Be Ready |
AvailableFreeSpace | Returns the amount of free space available on the drive in bytes. | Yes |
DriveFormat | Returns the name of the filesystem type such as NTFS (NT File System) or FAT32 (32-bit File Allocation Table). (For a comparison of these, see www.ntfs.com/ntfs_vs_fat.htm.) | Yes |
DriveType | Returns a DriveType enumeration value indicating the drive type. This value can be CDRom , Fixed , Network , NoRootDirectory , Ram , Removable , or Unknown . | No |
IsReady | Returns true if the drive is ready. | No |
Name | Returns the drive’s name. This is the drive’s root name (as in A: or C: ). | No |
RootDirectory | Returns a DirectoryInfo object representing the drive’s root directory. (See the following section “DirectoryInfo ” for more information on this class.) | No |
TotalFreeSpace | Returns the total amount of free space on the drive in bytes. | Yes |
VolumeLabel | Gets or sets the drive’s volume label. | Yes |
The DriveInfo
class also has a public static GetDrives
method 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 |
Attributes | Gets or sets the directory’s attributes. This is a combination of FileAttributes flags that can include Archive , Compressed , Device , Directory , Encrypted , IntegrityStream , Hidden , Normal , NoScrubData , NotContextIndexed , Offline , ReadOnly , ReparsePoint , SparseFile , System , and Temporary . |
Create | Creates the directory. (Create a DirectoryInfo object, passing its constructor the fully qualified name of a directory that doesn’t exist, and then use the Create method to create the directory.) |
CreateSubdirectory | Creates a subdirectory within the directory and returns a DirectoryInfo object representing it. The subdirectory’s path is relative to the DirectoryInfo object’s directory, but can contain intermediate subdirectories. |
CreationTime | Gets or sets the directory’s creation time. |
CreationTimeUtc | Gets or sets the directory’s creation time in UTC. |
Delete | Deletes the directory if it is empty. A parameter lets you tell the object to delete its contents, too, if it isn’t empty. |
Exists | Returns true if the directory exists. |
Extension | Returns the extension part of the directory’s name. Normally, this is an empty string for directories. |
FullName | Returns the directory’s fully qualified path. |
GetDirectories | 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. |
GetFiles | 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. |
GetFileSystemInfos | 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. |
LastAccessTime | Gets or sets the directory’s last access time. |
LastAccessTimeUtc | Gets or sets the directory’s last access time in UTC. |
LastWriteTime | Gets or sets the directory’s last write time. |
LastWriteTimeUtc | Gets or sets directory’s last write time in UTC. |
MoveTo | Moves the directory and its contents to a new path. |
Name | The directory’s name without the path information. |
Parent | Returns a DirectoryInfo object, representing the directory’s parent. If the directory is its file system’s root (for example, C: ), this returns null . |
Refresh | Refreshes the DirectoryInfo object’s data. |
Root | Returns a DirectoryInfo object representing the root of the directory’s file system. |
ToString | 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 files. The following table describes the most useful public properties and methods provided by the FileInfo
class.
Property or Method | Purpose |
AppendText | Returns a StreamWriter that appends text to the file. |
Attributes | Gets or sets the file’s attributes. This is a combination of FileAttributes flags that can include Archive , Compressed , Device , Directory , Encrypted , IntegrityStream , Hidden , Normal , NoScrubData , NotContextIndexed , Offline , ReadOnly , ReparsePoint , SparseFile , System , and Temporary . |
CopyTo | 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. |
Create | Creates the file and returns a FileStream object attached to it. (Create a FileInfo object, passing its constructor the name of a file that doesn’t exist, and then call the Create method to create the file.) |
CreateText | Creates the file and returns a StreamWriter attached to it. (Create a FileInfo object, passing its constructor the name of a file that doesn’t exist, and then call the CreateText method to create the file.) |
CreationTime | Gets or sets the file’s creation time. |
CreationTimeUtc | Gets or sets the file’s creation time in UTC. |
Delete | Deletes the file. |
Directory | Returns a DirectoryInfo object representing the file’s directory. |
DirectoryName | Returns the name of the file’s directory. |
Exists | Returns true if the file exists. |
Extension | Returns the extension part of the file’s name. For example, the extension for scores.txt is .txt . |
FullName | Returns the file’s fully qualified path and name. |
IsReadOnly | Returns true if the file is marked read-only. |
LastAccessTime | Gets or sets the file’s last access time. |
LastAccessTimeUtc | Gets or sets the file’s last access time in UTC. |
LastWriteTime | Gets or sets the file’s last write time. |
LastWriteTimeUtc | Gets or sets the file’s last write time in UTC. |
Length | Returns the number of bytes in the file. |
MoveTo | 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. |
Name | The file’s name without the path information. |
Open | 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. |
OpenRead | Returns a read-only FileStream attached to the file. |
OpenText | Returns a StreamReader with UTF-8 encoding attached to the file for reading. |
OpenWrite | Returns a write-only FileStream attached to the file. |
Refresh | Refreshes the FileInfo object’s data. |
Replace | 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. |
ToString | Returns the file’s fully qualified name. |
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, a FileSystemWatcher
can monitor a directory and raise an event when a new file appears so your program can 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 *.txt
makes it watch for changes to text files. The default filter is *.*
, which catches changes to all files that have extensions.
The following table describes the FileSystemWatcher
class’s most useful properties.
Property | Purpose |
EnableRaisingEvents | Determines whether the watcher is enabled. (This property is false by default, so the watcher does not raise any events until you set it to true .) |
Filter | 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 s.) |
IncludeSubdirectories | Determines whether the object watches subdirectories below the main directory. |
InternalBufferSize | Determines the size of the internal buffer. If the watcher is monitoring a very active directory, a small buffer may overflow. |
NotifyFilter | 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 . |
Path | Determines the path of the directory to watch. |
The FileSystemWatcher
class provides only two useful methods. The first method, Dispose
, releases resources used by the component. As usual, be sure to call Dispose
when you are done with the object (or use a using
statement).
The second method, WaitForChanged
, 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 |
Changed | A file or subdirectory has changed. |
Created | A file or subdirectory was created. |
Deleted | A file or subdirectory was deleted. |
Error | The watcher’s internal buffer overflowed. |
Renamed | A file or subdirectory was renamed. |
The Path
class provides static properties and methods that you can use to manipulate paths. Its methods return the path’s filename, extension, directory name, and so forth.
Other methods provide values that relate to system-generated paths. 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 |
AltDirectorySeparatorChar | Returns the alternative character used to separate directory levels in a hierarchical path. Typically, this is / . |
DirectorySeparatorChar | Returns the character normally used to separate directory levels in a hierarchical path. Typically, this is (as in C:UsersRodPhoneProjectsMrBones.sln ). |
InvalidPathChars | 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. |
PathSeparator | Returns the character used to separate path strings in environment variables. Typically, this is a semicolon (; ). |
VolumeSeparatorChar | Returns the character placed between a volume letter and the rest of the path. Typically, this is a colon (: ) as in C: . |
The following table describes the Path
class’s most useful methods.
Method | Purpose |
ChangeExtension | Changes a path’s extension. |
Combine | Returns two path strings concatenated. |
GetDirectoryName | Returns a path’s directory. |
GetExtension | Returns a path’s extension. |
GetFileName | Returns a path’s filename and extension. |
GetFileNameWithoutExtension | Returns a path’s filename without the extension. |
GetFullPath | Returns a path’s fully qualified value. |
GetInvalidFileNameChars | Returns an array listing characters that are invalid in filenames. |
GetInvalidPathChars | Returns an array listing characters that are invalid in file paths. |
GetPathRoot | Returns a path’s root directory string. |
GetRandomFileName | Returns a random filename. |
GetTempFileName | 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 filename might be C:UsersRodAppDataLocalTemp mpD4F0.tmp . |
GetTempPath | Returns the path to the system’s temporary folder. This is the path part of the filenames returned by GetTempFileName . |
HasExtension | Returns true if a path includes an extension. |
IsPathRooted | Returns true if a path is an absolute path. This includes C:TestsLogs.txt and ClientsLitigation , but not LostFilesPeter.txt or .Jokes . |
Unfortunately, C# doesn’t include methods for working with the recycle bin. However, you can use a combination of three different techniques: using the FileIO.FileSystem
class, using API functions, and using Shell32.Shell
.
The ManageRecycleBin example program, which is available for download on this book’s website, demonstrates the techniques described in the following sections. Enter a file or directory name and click the corresponding Delete button to move that item into the recycle bin. Click Refresh to refresh the list of files in the recycle bin. Click Empty to permanently remove all the files from the recycle bin. Finally, right-click a file in the recycle bin to see a context menu giving commands you can apply to that file, as shown in Figure 19-1.
You may want to download the ManageRecycleBin example program so that you can refer to it as you read the following sections.
The Microsoft.VisualBasic.FileIO
namespace includes a FileSystem
class that provides DeleteDirectory
and DeleteFile
methods. Those methods can take an optional parameter that indicates whether you want to move the directory or file into the recycle bin, or whether you want to delete the directory or file permanently. (They can also take a parameter that lets you decide whether the methods should display progress dialogs.)
Some C# developers prefer not to use classes defined in the Microsoft.VisualBasic
namespace, feeling they are somehow not C#ish enough. Personally, I think that’s just plain silly. If the Microsoft.VisualBasic
namespace includes tools that you can use to make your life easier, you’re only hurting yourself by ignoring them. This class is in the .NET Framework, so it’s not like you’re sneaking around using some sort of substandard back alley code.
The following code shows the event handlers the ManageRecycleBin program executes when you click one of its Delete buttons.
// Delete a file.
private void deleteFileButton_Click(object sender, EventArgs e)
{
FileSystem.DeleteFile(fileTextBox.Text,
UIOption.OnlyErrorDialogs, RecycleOption.SendToRecycleBin);
fileTextBox.Clear();
ListFiles();
}
// Delete a directory.
private void deleteDirectoryButton_Click(object sender, EventArgs e)
{
FileSystem.DeleteDirectory(directoryTextBox.Text,
UIOption.OnlyErrorDialogs, RecycleOption.SendToRecycleBin);
directoryTextBox.Clear();
ListFiles();
}
The first event handler deletes a file. It calls the FileSystem
class’s DeleteFile
method, passing it the name of the file to delete, a UIOption
flag indicating the method should display only error messages (not animations or confirmation dialogs), and a RecycleOption
value indicating the file should be moved to the recycle bin.
The code then clears the TextBox
holding the file’s name and calls the ListFiles
method. The ListFiles
method uses Shell32.Shell
, which is described shortly in the section “Using Shell32.Shell
.”
The FileIO.FileSystem
class lets you easily move directories and files into the recycle bin, but it doesn’t give you any other tools for working with the recycle bin. It doesn’t let you determine the number or sizes of the items in the recycle bin, restore items from the recycle bin, or empty the recycle bin.
Fortunately, you can use the SHEmptyRecycleBin
API function to empty the recycle bin relatively easily. This API function takes a parameter that is of the RecycleFlags
enumerated type. (Actually, the function itself takes a uint
as a parameter, but the enumeration makes it easier for your code to specify the wanted options.) The following code shows the enumeration’s definition.
[Flags]
private enum RecycleFlags : uint
{
SHERB_NOCONFIRMATION = 0x1,
SHERB_NOPROGRESSUI = 0x2,
SHERB_NOSOUND = 0x4
}
The following code shows the API function’s declaration.
[DllImport("shell32.dll")]
static extern int SHEmptyRecycleBin(
IntPtr hWnd, string pszRootPath, uint dwFlags);
Here shell32.dll is the library that contains the SHEmptyRecycleBin
API function. This is different from the Shell32.Shell
techniques described in the next section.
The ManageRecycleBin program uses the following EmptyRecycleBin
method, which wraps the call to SHEmptyRecycleBin
.
public static void EmptyRecycleBin(bool showProgress, bool playSound,
bool confirm)
{
RecycleFlags options = 0;
if (!showProgress) options |= RecycleFlags.SHERB_NOPROGRESSUI;
if (!playSound) options |= RecycleFlags.SHERB_NOSOUND;
if (!confirm) options |= RecycleFlags.SHERB_NOCONFIRMATION;
SHEmptyRecycleBin(IntPtr.Zero, null, (uint)options);
}
This method uses its parameters to create an appropriate RecycleFlags
value. It then simply invokes the API function.
When you click the Empty button, the program uses the following code to invoke the EmptyRecycleBin
method.
// Empty the recycle bin.
private void emptyButton_Click(object sender, EventArgs e)
{
// Empty with sounds and making the user confirm.
EmptyRecycleBin(false, true, true);
// Refresh the list.
ListFiles();
}
Shell32.Shell
is an interface for working with the Windows shell. One of the things you can do with the Shell
interface is interact with virtual objects representing such things as remote printers and the recycle bin.
The files in the recycle bin are represented by FolderItem
s. To work with the files, the ManageRecycleBin program needs to keep track of those FolderItem
s. To do so, it stores information about the files in the following RecycleItemInfo
class.
// A class to hold a FolderItem and return its name.
private class RecycleItemInfo
{
public FolderItem Item;
public RecycleItemInfo(FolderItem item)
{
Item = item;
}
public override string ToString()
{
return Item.Name;
}
}
This class simply holds a FolderItem
. It provides a constructor for easy initialization and overrides its ToString
method to return the name of the file it represents.
The following code shows the ManageRecycleBin program’s ListFiles
method.
// List the files in the recycle bin.
private void ListFiles()
{
const int RECYCLE_BIN_NAMESPACE = 10;
Shell shell = new Shell();
Folder bin = shell.NameSpace(RECYCLE_BIN_NAMESPACE);
// List the files.
filesListBox.Items.Clear();
foreach (FolderItem item in bin.Items())
{
filesListBox.Items.Add(new RecycleItemInfo(item));
}
}
The method creates a new Shell
interface and uses its NameSpace
method to get a Folder
interface representing the recycle bin. The parameter, which has value 10, is simply the “magic number” that represents the recycle bin.
Next, the method empties the file ListBox
and loops through the FolderItem
s returned by the recycle Folder
’s Items
method. For each FolderItem
, the program creates a RecycleItemInfo
object and adds it to the ListBox
.
Because the RecycleItemInfo
class’s ToString
method returns the FolderItem
’s Name
property, that is what is displayed by the ListBox
.
The following code shows how the program responds when you right-click a file’s entry in the ListBox
.
// On right-mouse down, display the item's verbs in a menu.
private void filesListBox_MouseDown(object sender, MouseEventArgs e)
{
// Make sure it's the right button.
if (e.Button != MouseButtons.Right) return;
// Find the item under the mouse.
int index = filesListBox.IndexFromPoint(e.Location);
if (index < 0) return;
// Select that item.
filesListBox.SelectedIndex = index;
// Get the item's RecycleItemInfo.
RecycleItemInfo info = filesListBox.SelectedItem as RecycleItemInfo;
// Get the item's FolderInfo object.
FolderItem item = info.Item;
// Make the context menu.
ContextMenu menu = new ContextMenu();
foreach (FolderItemVerb verb in item.Verbs())
{
MenuItem menuItem = new MenuItem(verb.Name, ContextMenuItem_Click);
menuItem.Tag = verb;
menu.MenuItems.Add(menuItem);
}
menu.Show(filesListBox, e.Location);
}
This code creates a context menu appropriate for the item that the user right-clicked. First, the method exits if the button pressed isn’t the right mouse button.
Next, the program uses the ListBox
’s IndexFromPoint
method to get the index of the item under the mouse. If there is no item there, the method exits. If there is an item below the mouse, the code selects it.
The code then converts the selected item into the RecycleItemInfo
object that is stored in the ListBox
and gets the FolderItem
stored inside the object.
The method then creates a ContextMenu
and loops through the list returned by the FolderItem
’s Verbs
method. Each of those items is a FolderItemVerb
interface that represents something the FolderItem
can do.
The code creates a new MenuItem
representing each verb. The MenuItem
displays its verb’s name and is associated with the ContextMenuItem_Click
event handler. The code stores the FolderItemVerb
in the MenuItem
’s Tag
property.
After it has created the ContextMenu
and the verbs’ MenuItem
s, the program displays the ContextMenu
.
The following code shows the ContextMenuItem_Click
event handler.
// Perform some action on a file.
private void ContextMenuItem_Click(object sender, EventArgs e)
{
// Get the MenuItem.
MenuItem menuItem = sender as MenuItem;
// Get the verb.
FolderItemVerb verb = menuItem.Tag as FolderItemVerb;
// Invoke the verb.
verb.DoIt();
// Redisplay the files.
ListFiles();
}
First, this code gets the MenuItem
that was clicked. It gets the corresponding FolderItemVerb
from the MenuItem
’s Tag
property. The code invokes the FolderItemVerb
’s DoIt
method to make it perform whatever action it should take. It finishes by calling ListFiles
to refresh the file list in case the verb changed the files in the recycle bin, for example, by restoring a file.
Download the ManageRecycleBin program to see additional details. The program isn’t exactly simple, but it does demonstrate techniques you can use to work with the recycle bin.
The System.IO
namespace offers many classes that let you manipulate files and directories. 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 ReadAllText
and WriteAllText
methods make it particularly easy to read or write an entire file.
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 you can use to combine paths and resolve relative paths.
There is considerable overlap among these tools, so you don’t need to feel that you have to use them all. Take a good look so that you know what’s there, and then pick the tools that you find the most comfortable.
Finally this chapter explained techniques you can use to manage the recycle bin. Some of them are fairly complex, but at least the FileIO.FileSystem
class makes moving a file or directory into the recycle reasonably simple.
So far the chapters in this book have explained how to do things locally on the user’s computer. The next chapter explains how a program can move off of the local computer to download files from the Internet.
CheckBox
es to display and let the user specify attributes.File.ReadAllText
and File.WriteAllText
to save and restore the contents of a text file when it starts and stops. Compare your solution to the solution for Exercise 18-3.File.ReadAllLines
to get the lines, sort them, and then use File.WriteAllLines
to write them back into the file.)DriveInfo
class.C:
?FileSystemWatcher
to watch the directory where the program is executing for changes. When a change occurs, the program should display the date and time, the type of change, and the changing file’s name.FileIO
class to move the file into the recycle bin. (That’s all many programs need to do anyway. You can use the recycle bin on your desktop to manage its contents.)