[ Team LiB ] |
21.1 Files and DirectoriesBefore looking at how you can get data into and out of files, let's start by examining the support provided for file and directory manipulation. The classes you need are in the System.IO namespace. These include the File class, which represents a file on disk, and the Directory class, which represents a directory (known in Windows as a folder). 21.1.1 Working with DirectoriesThe Directory class exposes static methods for creating, moving, and exploring directories. All the methods of the Directory class are static, and therefore you can call them all without having an instance of the class. The DirectoryInfo class is a similar class, but one which has nothing but instance members (i.e., no static members at all). DirectoryInfo derives from FileSystemInfo, which in turn derives from MarshalByRefObject. The FileSystemInfo class has a number of properties and methods that provide information about a file or directory. Table 21-1 lists the principal methods of the Directory class, and Table 21-2 lists the principal methods of the DirectoryInfo class, including important properties and methods inherited from FileSystemInfo.
21.1.2 Creating a DirectoryInfo ObjectTo explore a directory hierarchy, you need to instantiate a DirectoryInfo object. The DirectoryInfo class provides methods for getting not just the names of contained files and directories, but also FileInfo and DirectoryInfo objects, allowing you to dive into the hierarchical structure, extracting subdirectories and exploring these recursively. Instantiate a DirectoryInfo object with the name of the directory you want to explore: string path = Environment.GetEnvironmentVariable("SystemRoot"); DirectoryInfo dir = new DirectoryInfo(path);
You can ask that DirectoryInfo object for information about itself, including its name, full path, attributes, the time it was last accessed, and so forth. To explore the subdirectory hierarchy, ask the current directory for its list of subdirectories: DirectoryInfo[] directories = dir.GetDirectories( ); This returns an array of DirectoryInfo objects, each of which represents a directory. You can then recurse into the same method, passing in each DirectoryInfo object in turn: foreach (DirectoryInfo newDir in directories) { dirCounter++; ExploreDirectory(newDir); } The dirCounter static int member variable keeps track of how many subdirectories have been found altogether. To make the display more interesting, add a second static int member variable indentLevel that will be incremented each time you recurse into a subdirectory, and decremented when you pop out. This will allow you to display the subdirectories indented under the parent directories. The complete listing is shown in Example 21-1. Example 21-1. Recursing through subdirectoriesnamespace Programming_CSharp { using System; using System.IO; class Tester { // static member variables to keep track of totals // and indentation level static int dirCounter = 1; static int indentLevel = -1; // so first push = 0 public static void Main( ) { Tester t = new Tester( ); // choose the initial subdirectory string theDirectory = Environment.GetEnvironmentVariable("SystemRoot"); // call the method to explore the directory, // displaying its access date and all // subdirectories DirectoryInfo dir = new DirectoryInfo(theDirectory); t.ExploreDirectory(dir); // completed. print the statistics Console.WriteLine( "\n\n{0} directories found.\n", dirCounter); } // Set it running with a directoryInfo object // for each directory it finds, it will call // itself recursively private void ExploreDirectory(DirectoryInfo dir) { indentLevel++; // push a directory level // create indentation for subdirectories for (int i = 0; i < indentLevel; i++) Console.Write(" "); // two spaces per level // print the directory and the time last accessed Console.WriteLine("[{0}] {1} [{2}]\n", indentLevel, dir.Name, dir.LastAccessTime); // get all the directories in the current directory // and call this method recursively on each DirectoryInfo[] directories = dir.GetDirectories( ); foreach (DirectoryInfo newDir in directories) { dirCounter++; // increment the counter ExploreDirectory(newDir); } indentLevel--; // pop a directory level } } } Output (excerpt): [2] logiscan [5/1/2001 3:06:41 PM] [2] miitwain [5/1/2001 3:06:41 PM] [1] Web [5/1/2001 3:06:41 PM] [2] printers [5/1/2001 3:06:41 PM] [3] images [5/1/2001 3:06:41 PM] [2] Wallpaper [5/1/2001 3:06:41 PM] 363 directories found. The program begins by identifying a directory (%SystemRoot%, usually C:\WinNT or C:\Windows) and creating a DirectoryInfo object for that directory. It then calls ExploreDirectory, passing in that DirectoryInfo object. ExploreDirectory displays information about the directory and then retrieves all the subdirectories. The list of all the subdirectories of the current directory is obtained by calling GetDirectories. This returns an array of DirectoryInfo objects. ExploreDirectory is the recursive method; each DirectoryInfo object is passed into ExploreDirectory in turn. The effect is to push recursively into each subdirectory, and then pop back out to explore sister directories until all the subdirectories of %SystemRoot% are displayed. When ExploreDirectory finally returns, the calling method prints a summary. 21.1.3 Working with FilesThe DirectoryInfo object can also return a collection of all the files in each subdirectory found. The GetFiles( ) method returns an array of FileInfo objects, each of which describes a file in that directory. The FileInfo and File objects relate to one another, much as DirectoryInfo and Directory do. Like the methods of Directory, all the File methods are static; like DirectoryInfo, all the methods of FileInfo are instance methods. Table 21-3 lists the principal methods of the File class, and Table 21-4 lists the important members of the FileInfo class.
Example 21-2 modifies Example 21-1, adding code to get a FileInfo object for each file in each subdirectory. That object is used to display the name of the file, along with its length and the date and time it was last accessed. Example 21-2. Exploring files and subdirectoriesnamespace Programming_CSharp { using System; using System.IO; class Tester { // static member variables to keep track of totals // and indentation level static int dirCounter = 1; static int indentLevel = -1; // so first push = 0 static int fileCounter = 0; public static void Main( ) { Tester t = new Tester( ); // choose the initial subdirectory string theDirectory = Environment.GetEnvironmentVariable("SystemRoot"); // call the method to explore the directory, // displaying its access date and all // subdirectories DirectoryInfo dir = new DirectoryInfo(theDirectory); t.ExploreDirectory(dir); // completed. print the statistics Console.WriteLine( "\n\n{0} files in {1} directories found.\n", fileCounter,dirCounter); } // Set it running with a directoryInfo object // for each directory it finds, it will call // itself recursively private void ExploreDirectory(DirectoryInfo dir) { indentLevel++; // push a directory level // create indentation for subdirectories for (int i = 0; i < indentLevel; i++) Console.Write(" "); // two spaces per level // print the directory and the time last accessed Console.WriteLine("[{0}] {1} [{2}]\n", indentLevel, dir.Name, dir.LastAccessTime); // get all the files in the directory and // print their name, last access time, and size FileInfo[] filesInDir = dir.GetFiles( ); foreach (FileInfo file in filesInDir) { // indent once extra to put files // under their directory for (int i = 0; i < indentLevel+1; i++) Console.Write(" "); // two spaces per level Console.WriteLine("{0} [{1}] Size: {2} bytes", file.Name, file.LastWriteTime, file.Length); fileCounter++; } // get all the directories in the current directory // and call this method recursively on each DirectoryInfo[] directories = dir.GetDirectories( ); foreach (DirectoryInfo newDir in directories) { dirCounter++; // increment the counter ExploreDirectory(newDir); } indentLevel--; // pop a directory level } } } Output (excerpt): [0] WinNT [5/1/2001 3:34:01 PM] Active Setup Log.txt [4/20/2001 10:42:22 AM] Size: 10620 bytes actsetup.log [4/20/2001 12:05:02 PM] Size: 8717 bytes Blue Lace 16.bmp [12/6/1999 4:00:00 PM] Size: 1272 bytes [2] Wallpaper [5/1/2001 3:14:32 PM] Boiling Point.jpg [4/20/2001 8:30:24 AM] Size: 28871 bytes Chateau.jpg [4/20/2001 8:30:24 AM] Size: 70605 bytes Windows 2000.jpg [4/20/2001 8:30:24 AM] Size: 129831 bytes 8590 files in 363 directories found. The example is initialized with the name of the %SystemRoot% directory. It prints information about all the files in that directory and then recursively explores all the subdirectories and all their subdirectories (your output might differ). This can take quite a while to run, because the %SystemRoot% directory tree is rather large (363 subdirectories on my machine, as shown in the output). 21.1.4 Modifying FilesAs you can see from Tables Table 21-3 and 21-4, it is possible to use the FileInfo class to create, copy, rename, and delete files. The next example will create a new subdirectory, copy files in, rename some, delete others, and then delete the entire directory.
The first step is to create a DirectoryInfo object for the test directory: string theDirectory = @"c:\test\media"; DirectoryInfo dir = new DirectoryInfo(theDirectory); Next, create a subdirectory within the test directory by calling CreateSubDirectory on the DirectoryInfo object. You get back a new DirectoryInfo object, representing the newly created subdirectory: string newDirectory = "newTest"; DirectoryInfo newSubDir = dir.CreateSubdirectory(newDirectory); You can now iterate over the test and copy files to the newly created subdirectory: FileInfo[] filesInDir = dir.GetFiles( ); foreach (FileInfo file in filesInDir) { string fullName = newSubDir.FullName + "\\" + file.Name; file.CopyTo(fullName); Console.WriteLine("{0} copied to newTest", file.FullName); } Notice the syntax of the CopyTo method. This is a method of the FileInfo object. Pass in the full path of the new file, including its full name and extension. Once you've copied the files, you can get a list of the files in the new subdirectory and work with them directly: filesInDir = newSubDir.GetFiles( ); foreach (FileInfo file in filesInDir) { Create a simple integer variable named counter and use it to rename every other file: if (counter++ %2 == 0) { file.MoveTo(fullName + ".bak"); Console.WriteLine("{0} renamed to {1}", fullName,file.FullName); } You rename a file by "moving" it to the same directory, but with a new name. You can, of course, move a file to a new directory with its original name, or you can move and rename at the same time. Rename every other file, and delete the ones you don't rename: file.Delete( ); Console.WriteLine("{0} deleted.", fullName); Once you're done manipulating the files, you can clean up by deleting the entire subdirectory: newSubDir.Delete(true); The Boolean parameter determines whether this is a recursive delete. If you pass in false, and if this directory has subdirectories with files in it, it throws an exception. Example 21-3 lists the source code for the complete program. Be careful when running this: when it is done, the subdirectory is gone. To see the renaming and deletions, either put a breakpoint on the last line or remove the last line. Example 21-3. Creating a subdirectory and manipulating filesnamespace Programming_CSharp { using System; using System.IO; class Tester { public static void Main( ) { // make an instance and run it Tester t = new Tester( ); string theDirectory = @"c:\test\media"; DirectoryInfo dir = new DirectoryInfo(theDirectory); t.ExploreDirectory(dir); } // Set it running with a directory name private void ExploreDirectory(DirectoryInfo dir) { // make a new subdirectory string newDirectory = "newTest"; DirectoryInfo newSubDir = dir.CreateSubdirectory(newDirectory); // get all the files in the directory and // copy them to the new directory FileInfo[] filesInDir = dir.GetFiles( ); foreach (FileInfo file in filesInDir) { string fullName = newSubDir.FullName + "\\" + file.Name; file.CopyTo(fullName); Console.WriteLine("{0} copied to newTest", file.FullName); } // get a collection of the files copied in filesInDir = newSubDir.GetFiles( ); // delete some and rename others int counter = 0; foreach (FileInfo file in filesInDir) { string fullName = file.FullName; if (counter++ %2 == 0) { file.MoveTo(fullName + ".bak"); Console.WriteLine("{0} renamed to {1}", fullName,file.FullName); } else { file.Delete( ); Console.WriteLine("{0} deleted.", fullName); } } newSubDir.Delete(true); // delete the subdirectory } } } Output (excerpts): c:\test\media\Bach's Brandenburg Concerto No. 3.RMI copied to newTest c:\test\media\Beethoven's 5th Symphony.RMI copied to newTest c:\test\media\Beethoven's Fur Elise.RMI copied to newTest c:\test\media\canyon.mid copied to newTest c:\test\media\newTest\Bach's Brandenburg Concerto No. 3.RMI renamed to c:\test\media\newTest\Bach's Brandenburg Concerto No. 3.RMI.bak c:\test\media\newTest\Beethoven's 5th Symphony.RMI deleted. c:\test\media\newTest\Beethoven's Fur Elise.RMI renamed to c:\test\media\newTest\Beethoven's Fur Elise.RMI.bak c:\test\media\newTest\canyon.mid deleted. |
[ Team LiB ] |