Working with Files and Directories


The System::IO namespace contains several classes to help you work with files and directories.

Getting Information About Files and Directories

The Directory and DirectoryInfo classes provide you with functions to help you work with directories. The difference between them is that the Directory class only contains static methods, while DirectoryInfo contains nonstatic instance methods. Why the need for two different classes? It’s necessary for .NET to perform a security check before allowing you access to a directory or a file. The Directory class performs this check every time you use one of its static methods, which can be time-consuming. Objects of the DirectoryInfo class, on the other hand, work with one directory, and the security check is done once when the object is constructed. It can, therefore, be a lot more efficient to use DirectoryInfo if you’re going to perform multiple operations on one directory. The following table lists the main methods of the Directory class.

Method

Description

CreateDirectory

Creates a directory

Delete

Deletes a directory, and optionally its subdirectories

Exists

Checks whether a directory exists

GetCreationTime

Gets the creation time of a directory

GetCurrentDirectory

Returns a string representing the path to the application’s current directory

GetDirectories

Gets an array of strings representing the names of subdirectories in a given directory

GetDirectoryRoot

Returns the root portion of a path

GetFiles

Gets an array of strings representing the names of the files in a given directory

GetFileSystemEntries

Gets an array of strings representing the names of the files and directories in a given directory

GetLastAccessTime

Gets the last access time for the directory

GetLastWriteTime

Gets the last write time for the directory

GetLogicalDrives

Gets a list of the logical drives on the computer

GetParent

Gets the parent directory of a specified directory

Move

Moves a directory and its contents

SetCreationTime

Sets the creation time for a directory

SetCurrentDirectory

Sets the application’s current directory

SetLastAccessTime

Sets the last access time for the directory

SetLastWriteTime

Sets the last write time for the directory

The following two tables list the properties and methods of the DirectoryInfo class.

Property

Description

Attributes

Gets or sets the FileAttributes for the directory

CreationTime

Gets or sets the creation time for the directory

Exists

Value is true if the directory path exists

Extension

Gets the extension part of the directory name

FullName

Gets the full path of the directory

LastAccessTime

Gets or sets the time when the directory was last accessed

LastWriteTime

Gets or sets the time when the directory was last written to

Name

Represents the name of the directory

Parent

Gets a DirectoryInfo object representing the parent of this directory

Root

Gets a DirectoryInfo object representing the root portion of a directory path

Method

Description

Create

Creates a directory

CreateSubdirectory

Creates one or more subdirectories

Delete

Deletes a directory and its contents

GetDirectories

Gets an array of DirectoryInfo objects representing the subdirectories of this directory

GetFiles

Gets an array of FileInfo objects representing the files in this directory

GetFileSystemInfos

Gets an array of FileSystemInfo objects representing the directories and files in this directory

MoveTo

Moves the directory and its contents

ToString

Returns the fully qualified path as a string

Two classes, File and FileInfo, are used to work with files. Like the Directory and DirectoryInfo classes discussed earlier, File contains static methods, and FileInfo contains nonstatic instance methods. The following table lists the methods provided by the File class.

Method

Description

AppendText

Appends text to a file, creating the file if it doesn’t already exist

Copy

Copies a file

Create

Creates a new file

CreateText

Creates a new text file

Delete

Deletes a file

Exists

Returns true if a file exists

GetAttributes

Returns the file attributes

GetCreationTime

Returns the file’s creation time

GetLastAccessTime

Returns the file’s last access time

GetLastWriteTime

Returns the file’s last write time

Move

Moves a file to a new location, with the option of renaming it

Open

Opens a FileStream for read/write access to a file

OpenRead

Opens a FileStream for read-only access to a file

OpenText

Opens a FileStream to read from a text file

OpenWrite

Opens a FileStream for read/write access to a file

SetAttributes

Sets the file attributes

SetCreationTime

Sets the file’s creation time

SetLastAccessTime

Sets the file’s last access time

SetLastWriteTime

Sets the file’s last write time

The following two tables list the properties and methods exposed by the FileInfo class.

Property

Description

Directory

Returns a DirectoryInfo object representing the file’s parent directory

DirectoryName

Returns a string representing the file’s full path

Exists

Returns true if the file exists

Length

Returns the length of the file in bytes

Name

Returns the name of the file

Method

Description

AppendText

Creates a StreamWriter to append text to a file

CopyTo

Copies a file to another location

Create

Creates a new file and a FileStream to write to it

CreateText

Creates a StreamWriter to write to a new text file

Delete

Deletes a file

MoveTo

Moves a file to a new location

Open

Returns a FileStream with a specified level of access to a file

OpenRead

Returns a FileStream with read access to a file

OpenText

Creates a StreamReader to read from an existing file

OpenWrite

Returns a FileStream with read/write access to a file

ToString

Returns the file path as a string

The following example illustrates the use of the directory and file manipulation classes. You’ll construct a simple directory-listing program similar in functionality to the MS-DOS dir command. Here’s how it will work:

  • If the path represents a file, the details of the file will be printed.

  • If the path represents a directory, the contents of the directory will be listed.

  • In addition to the name, the user can choose to display size, last modification date, and attributes. For directories, only the last modification date applies.

  1. Start a new Visual C++ Console Application (.NET) project named CppFiles.

  2. Because all the file and directory classes are part of System::IO, include a using declaration at the start of the program, as follows:

    using namespace System::IO;
  3. The user will use the command line to give options and a path to list, so edit the definition of the _tmain function to include the command- line argument parameters, just as you did in the CppReader exercise.

    int _tmain(int argc, char* argv[])
  4. The user can call the program with a path or with options plus a path. Add the following code to the _tmain function:

    // Check for required arguments if (argc < 2) { Console::WriteLine(S"Usage: CppFiles [options] [path]"); return 0; }

    The array of command-line arguments includes everything on the command line, so the first item will always be the program name. Therefore, we always want at least two arguments if we want the user to include a path.

  5. If the user has specified options, we need to find out what they are. Each option is specified by a single letter, and the set of options chosen is represented by a string of option letters. The options supported in this simple program are s for the size, d for the last modification date, and a for attributes. It doesn’t matter what order options are given in, so sa and as would both print the size and attributes.

    Here’s the code to check the arguments and save the path and the options that the user has specified:

    String* options = 0; String* path = 0; bool bGotOptions = false; // Split out the arguments if (argc == 3) { bGotOptions = true; options = new String(argv[1]); path = new String(argv[2]); } else if (argc == 2) path = new String(argv[1]); 

    If there are three command-line arguments, interpret the first one as an option string.

  6. Check which options the user has selected, using the following code:

    bool bSize = false; bool bDate = false; bool bAtts = false; // If we have options, check them. The default is to list // the name only // Possible options are: // v verbose listing, gives name, size & access time // s list size // d list last access date // a list attributes if (bGotOptions) { options = options->ToLower(); if (options->IndexOf(‘v’) != -1) { bSize = true; bDate = true; bAtts = true; } else { if (options->IndexOf(‘s’) != -1) bSize = true; if (options->IndexOf(‘d’) != -1) bDate = true; if (options->IndexOf(‘a’) != -1) bAtts = true; } }

    Three Boolean variables represent the option choices. If v for verbose has been entered, all options are set. Otherwise, the individual option letters are checked and the corresponding bool variables are set accordingly.

  7. Determine whether the path that has been entered is a file or a directory. Here’s the code to do so:

    // Check whether the user has entered a file or a directory bool bItsAFile = false; bool bItsADirectory = false; FileInfo* fi = new FileInfo(path); DirectoryInfo* di = new DirectoryInfo(path); if (fi->Exists) bItsAFile = true; else if (di->Exists) bItsADirectory = true; if (!bItsAFile && !bItsADirectory) { Console::WriteLine(S"No such file or directory"); return(-1); }

    It isn’t as straightforward as you might expect to check whether a file or a directory has been entered. You have to use the Exists property of the FileInfo and DirectoryInfo classes to check whether the path you have is a file or a directory. If it’s a file, Exists will return true for FileInfo and false for DirectoryInfo, and vice versa if it’s a directory. Either bItsAFile or bItsADirectory might be set. If you end up with neither set, the path specified on the command line cannot be found; the application displays a message and exits, returning -1 as an error code.

  8. Now that you know what sort of object you have and what options the user wants, you can print out the details. The first case will be the details for a single file.

    // Process files if (bItsAFile) { Console::Write(Sfi->Name); if (bSize) Console::Write(S" {0}", __box(fi->Length)); if (bDate) Console::Write(S" {0}", File::GetLastAccessTime(fi->ToString()).ToString()); if (bAtts) { FileAttributes fa = File::GetAttributes(fi->ToString()); Console::Write(S" "); if (fa & FileAttributes::Normal) Console::Write(S"<normal>"); else { if (fa & FileAttributes::Archive) Console::Write(S"a"); if (fa & FileAttributes::Hidden) Console::Write(S"h"); if (fa & FileAttributes::System) Console::Write(S"s"); if (fa & FileAttributes::ReadOnly) Console::Write(S"r"); } } Console::WriteLine(S); } 

    The program always echoes the file name and then displays other information based on the options required by the user. The Length property needs to be boxed before it can be printed using Write. You have to get the last access time by using one of the static methods of the File class, which takes the file path as an argument; the easiest way to get the path is to use the ToString method of FileInfo.

    If the user has requested attributes, use the GetAttributes static member of File to get a FileAttributes object, and then use the bitwise AND operator (&) to match it against the various permissions defined in FileAttributes. This code is checking only four attributes; it would be easy to extend it to check more.

  9. If the user has entered a directory path, list the contents of the directory. The following code lists subdirectories first and files second, and it lists directory names in uppercase and files in lowercase; you can obviously change this code to display these items however you prefer. Let’s start with the code for listing the subdirectories.

    else if (bItsADirectory) { // List the directory contents - subdirs first, then files String* dirs[] = Directory::GetDirectories(di->ToString()); for(int i=0; i<dirs->Count; i++) { DirectoryInfo* sdi = new DirectoryInfo(dirs->get_Item(i)->ToString()); // Directories list in upper case String* dirName = sdi->Name->ToUpper(); Console::Write(S"{0,30}",dirName); // no size, so put a few blanks String* ss = S"—"; Console::Write(S"{0,12}",ss); // last mod date is OK if (bDate) Console::Write(S" {0}", Directory::GetLastAccessTime( sdi->ToString()).ToString()); // no attributes, either // finish the line Console::WriteLine(S); } } 

    The Directory::GetDirectories function returns an array of strings representing the names of the subdirectories in the current directory. Because this is a .NET array, you can use the Count property to determine how many elements it has. For each array element, you create a DirectoryInfo object using the path name returned when ToString is called on the element.

    The name is converted to uppercase and then printed out. Notice the use of a field width in the Write statement: format specifiers can take an optional field width after the field number. If this value is positive, the item is right justified in the field; if it’s negative, the item is left justified. A field width of 30 characters should be wide enough for most directory names. Directories don’t have a size, so output two hyphens as the size field. They do have a last access time, which can be obtained from the Directory class.

  10. Process the file entries. This code follows the same pattern as that for the subdirectories but also includes some of the code from the single- file case:

    // Now do the files String* files[] = Directory::GetFiles(di->ToString()); for(i=0; i<files->Count; i++) { FileInfo* fci = new FileInfo(files->get_Item(i)->ToString()); // Files list in lower case String* fileName = fci->Name->ToLower(); Console::Write(S"{0,30}",fileName); if (bSize) Console::Write(S"{0,12}", __box(fci->Length)); if (bDate) Console::Write(S"  {0}", File::GetLastAccessTime (fci->ToString()).ToString()); // Attributes if (bAtts) { FileAttributes fa = File::GetAttributes(fci->ToString()); Console::Write(S" "); if (fa & FileAttributes::Normal) Console::Write(S"<normal>"); else { if (fa & FileAttributes::Archive) Console::Write(S"a"); if (fa & FileAttributes::Hidden) Console::Write(S"h"); if (fa & FileAttributes::System) Console::Write(S"s"); if (fa & FileAttributes::ReadOnly) Console::Write(S"r"); } } // finish the line Console::WriteLine(S); } 

    The Directory::GetFiles static method returns an array of strings representing the files in the current directory. As before, you construct an object to represent each file and then query it. You do this exactly the same way as for the single-file case earlier in the exercise.

  11. Build the application, open a console window, change to the project’s Debug directory, and run the program with a suitable command line, such as the following:

    CppFiles sa .

    You should see output similar to the following figure, which lists the files in the project directory.

    click to expand

Tip

If you want to run the program under the Microsoft Visual Studio .NET debugger, you will need to provide the command-line arguments for the application. To do so, bring up the property pages for the project, select the Debugging option under Configuration Properties, and enter the arguments in the Command Arguments edit control. You can now run the program in debug mode.




Microsoft Visual C++  .NET(c) Step by Step
Microsoft Visual C++ .NET(c) Step by Step
ISBN: 735615675
EAN: N/A
Year: 2003
Pages: 208

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net