Classes File and Directory

Một phần của tài liệu Visual C 2012 How to Program _ www.bit.ly/taiho123 (Trang 714 - 723)

2. When the app executes, another compiler (known as the just-in-time compiler

17.4 Classes File and Directory

enables a program to input data from the keyboard.Console.Outrefers to thestandard out- put stream object, which enables a program to output data to the screen.Console.Error

refers to thestandard error stream object, which enables a program to output error messages to the screen. We’ve been usingConsole.OutandConsole.Inin our console apps,Console methodsWriteandWriteLineuseConsole.Outto perform output, andConsolemethods

ReadandReadLineuseConsole.Into perform input.

There are many file-processing classes in the Framework Class Library. The

System.IOnamespaceincludes stream classes such asStreamReader(for text input from a file),StreamWriter(for text output to a file) andFileStream(for both input from and output to a file). These stream classes inherit fromabstractclassesTextReader,Text-

WriterandStream, respectively. Actually, propertiesConsole.InandConsole.Outare of typeTextReaderandTextWriter, respectively. The system creates objects ofTextReader and TextWriter derived classes to initialize Console properties Console.In andCon-

sole.Out.

Abstract classStreamprovides functionality for representing streams as bytes. Classes

FileStream,MemoryStreamandBufferedStream(all from namespaceSystem.IO) inherit from classStream. ClassFileStreamcan be used to write data to and read data from files.

Class MemoryStreamenables the transfer of data directly to and from memory—this is much faster than reading from and writing to external devices. ClassBufferedStreamuses bufferingto transfer data to or from a stream. Buffering is an I/O performance-enhance- ment technique, in which each output operation is directed to a region in memory, called abuffer, that’s large enough to hold the data frommanyoutput operations. Then actual transfer to the output device is performed in one largephysical output operationeach time the buffer fills. The output operations directed to the output buffer in memory often are calledlogical output operations. Buffering can also be used to speed input operations by initially reading more data than is required into a buffer, so subsequent reads get data from high-speed memory rather than a slower external device.

In this chapter, we use key stream classes to implement file-processing programs that create and manipulate sequential-access files.

17.4 Classes File and Directory

Information is stored in files, which are organized in directories (also called folders). Classes

FileandDirectoryenable programs to manipulate files and directories on disk. ClassFile can determine information about files and can be used to open files for reading or writing.

We discuss techniques for writing to and reading from files in subsequent sections.

Figure 17.3 lists several of classFile’sstaticmethods for manipulating and deter- mining information about files. We demonstrate several of these methods in Fig. 17.5.

Fig. 17.2 | C#’s view of ann-byte file.

0 1 2 3 4 5 6 7 8 9 ...

...

n-1

end-of-file marker

ClassDirectoryprovides capabilities for manipulating directories. Figure 17.4 lists some of classDirectory’sstaticmethods for directory manipulation. Figure 17.5 dem- onstrates several of these methods, as well. TheDirectoryInfoobject returned by method

CreateDirectorycontains information about a directory. Much of the information con- tained in classDirectoryInfoalso can be accessed via the methods of classDirectory.

staticMethod Description

AppendText Returns aStreamWriterthat appends text to an existing file or creates a file if one does not exist.

Copy Copies a file to a new file.

Create Creates a file and returns its associatedFileStream.

CreateText Creates a text file and returns its associatedStreamWriter.

Delete Deletes the specified file.

Exists Returnstrueif the specified file exists andfalseotherwise.

GetCreationTime Returns aDateTimeobject representing when the file was created.

GetLastAccessTime Returns aDateTimeobject representing when the file was last accessed.

GetLastWriteTime Returns aDateTimeobject representing when the file was last modified.

Move Moves the specified file to a specified location.

Open Returns aFileStreamassociated with the specified file and equipped with the specified read/write permissions.

OpenRead Returns a read-onlyFileStreamassociated with the specified file.

OpenText Returns aStreamReaderassociated with the specified file.

OpenWrite Returns a writeFileStreamassociated with the specified file.

Fig. 17.3 | Fileclassstaticmethods (partial list).

staticMethod Description

CreateDirectory Creates a directory and returns its associatedDirectoryInfoobject.

Delete Deletes the specified directory.

Exists Returnstrueif the specified directory exists andfalseotherwise.

GetDirectories Returns astringarray containing the names of the subdirectories in the specified directory.

GetFiles Returns astringarray containing the names of the files in the speci- fied directory.

GetCreationTime Returns aDateTimeobject representing when the directory was created.

GetLastAccessTime Returns aDateTimeobject representing when the directory was last accessed.

GetLastWriteTime Returns aDateTimeobject representing when items were last written to the directory.

Move Moves the specified directory to a specified location.

Fig. 17.4 | Directoryclassstaticmethods.

17.4 ClassesFileandDirectory 675

Demonstrating ClassesFileandDirectory

.ClassFileTestForm(Fig. 17.5) usesFileandDirectorymethods to access file and direc- tory information. TheFormcontains theinputTextBox, in which the user enters a file or di- rectory name. For each key that the user presses while typing in theTextBox, the program callsinputTextBox_KeyDown(lines 19–75). If the user presses theEnterkey (line 22), this method displays either the file’s or directory’s contents, depending on the text the user input.

(If the user does not press theEnterkey, this method returns without displaying any con- tent.) Line 28 usesFilemethodExiststo determine whether the user-specified text is the name of an existing file. If so, line 31 invokesprivatemethodGetInformation(lines 79–

97), which callsFilemethodsGetCreationTime(line 88),GetLastWriteTime(line 92) and

GetLastAccessTime(line 96) to access file information. When methodGetInformationre- turns, line 38 instantiates aStreamReaderfor reading text from the file. TheStreamReader

constructor takes as an argument astringcontaining the name and path of the file to open.

Line 40 callsStreamReadermethodReadToEndto read the entire contents of the file as a

string, then appends thestringtooutputTextBox. Once the file has been read, theusing

block terminates and disposes of the corresponding object, which closes the file.

1 // Fig. 17.5: FileTestForm.cs

2 // Using classes File and Directory.

3 using System;

4 using System.Windows.Forms;

5 using System.IO;

6

7 namespace FileTest 8 {

9 // displays contents of files and directories 10 public partial class FileTestForm : Form

11 {

12 // parameterless constructor 13 public FileTestForm()

14 {

15 InitializeComponent();

16 } // end constructor 17

18 // invoked when user presses key

19 private void inputTextBox_KeyDown( object sender, KeyEventArgs e )

20 {

21 // determine whether user pressed Enter key 22 if ( e.KeyCode == Keys.Enter )

23 {

24 // get user-specified file or directory 25 string fileName = inputTextBox.Text;

26

27 // determine whether fileName is a file

28 if ( )

29 {

30 // get file's creation date, modification date, etc.

31 GetInformation( fileName );

32 StreamReader stream = null; // declare StreamReader 33

Fig. 17.5 | Using classesFileandDirectory.(Part 1 of 3.)

File.Exists( fileName )

34 // display file contents through StreamReader

35 try

36 {

37 // obtain reader and file contents

38 using ( stream = new StreamReader( fileName ) )

39 {

40 outputTextBox.AppendText( stream.ReadToEnd() );

41 } // end using

42 } // end try

43 catch ( IOException )

44 {

45 MessageBox.Show( "Error reading from file",

46 "File Error", MessageBoxButtons.OK,

47 MessageBoxIcon.Error );

48 } // end catch

49 } // end if

50 // determine whether fileName is a directory 51 else if ( Directory.Exists( fileName ) )

52 {

53 // get directory's creation date,

54 // modification date, etc.

55 GetInformation( fileName );

56

57 // obtain directory list of specified directory 58

59 60

61 outputTextBox.AppendText( "Directory contents:\n" );

62

63 // output directoryList contents

64 foreach ( var directory in directoryList ) 65 outputTextBox.AppendText( directory + "\n" );

66 } // end else if

67 else

68 {

69 // notify user that neither file nor directory exists 70 MessageBox.Show( inputTextBox.Text +

71 " does not exist", "File Error",

72 MessageBoxButtons.OK, MessageBoxIcon.Error );

73 } // end else

74 } // end if

75 } // end method inputTextBox_KeyDown 76

77 // get information on file or directory, 78 // and output it to outputTextBox

79 private void GetInformation( string fileName )

80 {

81 outputTextBox.Clear();

82

83 // output that file or directory exists

84 outputTextBox.AppendText( fileName + " exists\n" );

85

Fig. 17.5 | Using classesFileandDirectory.(Part 2 of 3.)

string[] directoryList =

Directory.GetDirectories( fileName );

17.4 ClassesFileandDirectory 677

If line 28 determines that the user-specified text is not a file, line 51 determines whether it’s a directory usingDirectory methodExists. If the user specified anexisting directory, line 55 invokes methodGetInformationto access the directory information.

Line 59 callsDirectorymethodGetDirectoriesto obtain astringarray containing the names of the subdirectories in the specified directory. Lines 64–65 display each element in thestringarray. Note that, if line 51 determines that the user-specified text isnota directory name, lines 70–72 notify the user (via aMessageBox) that the name the user entered does not exist as a file or directory.

Searching Directories with LINQ

We now consider another example that uses file- and directory-manipulation capabilities.

Class LINQToFileDirectoryForm (Fig. 17.6) uses LINQ with classes File, Path and 86 // output when file or directory was created

87 outputTextBox.AppendText( "Created: " +

88 + "\n" );

89

90 // output when file or directory was last modified 91 outputTextBox.AppendText( "Last modified: " +

92 + "\n" );

93

94 // output when file or directory was last accessed 95 outputTextBox.AppendText( "Last accessed: " +

96 + "\n" );

97 } // end method GetInformation 98 } // end class FileTestForm 99 } // end namespace FileTest

Fig. 17.5 | Using classesFileandDirectory.(Part 3 of 3.)

File.GetCreationTime( fileName )

File.GetLastWriteTime( fileName )

File.GetLastAccessTime( fileName )

b) Viewing all files in directoryC:\Program Files\

a) Viewing the contents of file"quotes.txt"

c) User gives invalid input d) Error message is displayed

Directoryto report the number of files of each file type that exist in the specified directory path. The program also serves as a “clean-up” utility—when it finds a file that has the.bak file-name extension (i.e., abackupfile), the program displays aMessageBoxasking the user whether that file should be removed, then responds appropriately to the user’s input. This example also usesLINQ to Objectsto help delete the backup files.

When the user clicksSearch Directory, the program invokessearchButton_Click

(lines 25–65), which searches recursively through the directory path specified by the user.

If the user inputs text in theTextBox, line 29 callsDirectorymethodExiststo determine whether that text is a valid directory. If it’s not, lines 32–33 notify the user of the error.

1 // Fig. 17.6: LINQToFileDirectoryForm.cs

2 // Using LINQ to search directories and determine file types.

3 using System;

4 using System.Collections.Generic;

5 using System.Linq;

6 using System.Windows.Forms;

7 using System.IO;

8

9 namespace LINQToFileDirectory 10 {

11 public partial class LINQToFileDirectoryForm : Form

12 {

13 string currentDirectory; // directory to search 14

15 // store extensions found, and number of each extension found 16

17

18 // parameterless constructor 19 public LINQToFileDirectoryForm()

20 {

21 InitializeComponent();

22 } // end constructor 23

24 // handles the Search Directory Button's Click event

25 private void searchButton_Click( object sender, EventArgs e )

26 {

27 // check whether user specified path exists 28 if ( pathTextBox.Text != string.Empty &&

29 )

30 {

31 // show error if user does not specify valid directory 32 MessageBox.Show( "Invalid Directory", "Error",

33 MessageBoxButtons.OK, MessageBoxIcon.Error );

34 } // end if

35 else

36 {

37 // use current directory if no directory is specified 38 if ( pathTextBox.Text == string.Empty )

39 currentDirectory = ;

Fig. 17.6 | Using LINQ to search directories and determine file types. (Part 1 of 4.)

Dictionary<string, int> found = new Dictionary<string, int>();

!Directory.Exists( pathTextBox.Text )

Directory.GetCurrentDirectory()

17.4 ClassesFileandDirectory 679

40 else

41 currentDirectory = pathTextBox.Text;

42

43 directoryTextBox.Text = currentDirectory; // show directory 44

45 // clear TextBoxes

46 pathTextBox.Clear();

47 resultsTextBox.Clear();

48

49 SearchDirectory( currentDirectory ); // search the directory 50

51 // allow user to delete .bak files 52 CleanDirectory( currentDirectory );

53

54 // summarize and display the results

55 foreach ( var current in )

56 {

57 // display the number of files with current extension 58 resultsTextBox.AppendText( string.Format(

59 "* Found {0} {1} files.\r\n",

60 , current ) );

61 } // end foreach

62 63

64 } // end else

65 } // end method searchButton_Click 66

67 // search directory using LINQ

68 private void SearchDirectory( string folder )

69 {

70 // files contained in the directory 71

72

73 // subdirectories in the directory 74

75

76 // find all file extensions in this directory 77 var extensions =

78 79 80

81 // count the number of files using each extension 82 foreach ( var extension in extensions )

83 {

84

85 // count the number of files with the extension

86 var extensionCount =

87 88 89 90 91

Fig. 17.6 | Using LINQ to search directories and determine file types. (Part 2 of 4.)

found.Keys

found[ current ]

found.Clear(); // clear results for new search

string[] files = Directory.GetFiles( folder );

string[] directories = Directory.GetDirectories( folder );

( from file in files

select Path.GetExtension( file ) ).Distinct();

( from file in files

where Path.GetExtension( file ) == extension select file ).Count();

92 // if the Dictionary already contains a key for the extension

93 if ( )

94 // update the count

95 else

96 // add new count

97 } // end foreach 98

99 // recursive call to search subdirectories 100 foreach ( var subdirectory in directories ) 101

102 } // end method SearchDirectory 103

104 // allow user to delete backup files (.bak) 105 private void CleanDirectory( string folder )

106 {

107 // files contained in the directory 108

109

110 // subdirectories in the directory 111

112

113 // select all the backup files in this directory 114 var backupFiles =

115 116 117 118

119 // iterate over all backup files (.bak) 120 foreach ( var backup in backupFiles )

121 {

122 DialogResult result = MessageBox.Show( "Found backup file " + 123 Path.GetFileName( backup ) + ". Delete?", "Delete Backup",

124 MessageBoxButtons.YesNo, MessageBoxIcon.Question );

125

126 // delete file if user clicked 'yes' 127 if ( result == DialogResult.Yes )

128 {

129 130 131

132 // if there are no .bak files, delete key from Dictionary 133 if ( found[ ".bak" ] == 0 )

134

135 } // end if

136 } // end foreach 137

138 // recursive call to clean subdirectories 139 foreach ( var subdirectory in directories ) 140

141 } // end method CleanDirectory 142 } // end class LINQToFileDirectoryForm 143 } // end namespace LINQToFileDirectory

Fig. 17.6 | Using LINQ to search directories and determine file types. (Part 3 of 4.)

found.ContainsKey( extension ) found[ extension ] += extensionCount;

found.Add( extension, extensionCount );

SearchDirectory( subdirectory );

string[] files = Directory.GetFiles( folder );

string[] directories = Directory.GetDirectories( folder );

from file in files

where Path.GetExtension( file ) == ".bak"

select file;

File.Delete( backup ); // delete backup file --found[ ".bak" ]; // decrement count in Dictionary

found.Remove( ".bak" );

CleanDirectory( subdirectory );

17.4 ClassesFileandDirectory 681

MethodSearchDirectory

Lines 38–41 get the current directory (if the user did not specify a path) or the specified directory. Line 49 passes the directory name torecursivemethodSearchDirectory(lines 68–102). Line 71 callsDirectorymethodGetFilesto get astringarray containing file names in the specified directory. Line 74 callsDirectorymethodGetDirectoriesto get astringarray containing the subdirectory names in the specified directory.

Lines 78–79 use LINQ to get theDistinctfile-name extensions in thefilesarray.

PathmethodGetExtensionobtains the extension for the specified file name. For each file- name extension returned by the LINQ query, lines 82–97 determine the number of occur- rences of that extension in thefilesarray. The LINQ query at lines 87–89 compares each file-name extension in thefilesarray with the current extension being processed (line 89). All matches are included in the result. We then use LINQ methodCountto determine the total number of files that matched the current extension.

ClassLINQToFileDirectoryFormuses aDictionary(declared in line 16) to store each file-name extension and the corresponding number of file names with that extension. A

Dictionary(namespaceSystem.Collections.Generic) is a collection ofkey–value pairs, in which eachkeyhas a correspondingvalue. ClassDictionaryis ageneric classlike class

List(presented in Section 9.4). Line 16 indicates that the Dictionary foundcontains pairs ofstrings andints, which represent the file-name extensions and the number of files with those extensions, respectively. Line 93 usesDictionarymethodContainsKeyto determine whether the specified file-name extension has been placed in theDictionary previously. If this method returnstrue, line 94 adds theextensionCountdetermined in lines 88–90 to the current total for that extension that’s stored in theDictionary. Other- wise, line 96 usesDictionarymethodAddto insert a newkey–value pairinto theDic- tionary for the new file-name extension and its extensionCount. Lines 100–101 recursively callSearchDirectoryfor each subdirectory in the current directory.

MethodCleanDirectory

When methodSearchDirectoryreturns, line 52 callsCleanDirectory(lines 105–141) to search for all files with extension.bak. Lines 108 and 111 obtain the list of file names and Fig. 17.6 | Using LINQ to search directories and determine file types. (Part 4 of 4.)

b) Dialog that appears to confirm deletion of a.bakfile

a) GUI after entering a directory to search and pressing Search Directory

list of directory names in the current directory, respectively. The LINQ query in lines 115–

117 locates all file names in the current directory that have the.bakextension. Lines 120–

136 iterate through the results and ask the user whether each file should be deleted. If the user clicksYesin the dialog, line 129 usesFilemethodDeleteto remove the file from disk, and line 130 subtracts 1 from the total number of.bakfiles. If the number of.bakfiles re- maining is0, line 134 usesDictionarymethodRemoveto delete the key–value pair for.bak files from theDictionary. Lines 139–140 recursively callCleanDirectoryfor each subdi- rectory in the current directory. After each subdirectory has been checked for .bakfiles, methodCleanDirectoryreturns, and lines 55–61 display the summary of file-name exten- sions and the number of files with each extension. Line 55 usesDictionarypropertyKeys to get all the keys. Line 60 uses theDictionary’s indexer to get the value for the current key.

Finally, line 63 usesDictionarymethodClearto delete the contents of theDictionary.

Một phần của tài liệu Visual C 2012 How to Program _ www.bit.ly/taiho123 (Trang 714 - 723)

Tải bản đầy đủ (PDF)

(1.020 trang)