Input and Output Classes

 A complete PDF version of the text book is now available. The PDF version is an almost complete subset of the HTML version (where only a few, long program listings have been removed). See here.

38.  Directories and Files

The previous chapter was about streams, and as such also about files. In this chapter we will deal with the properties of files beyond reading and writing. File copying, renaming, creation time, existence, and deletion represent a few of these. In addition to files we will also in this chapter discuss directories.

38.1.  The File and FileInfo classes
Contents   Up Previous Next   Slide Annotated slide Aggregated slides    Subject index Program index Exercise index

Two overlapping file-related classes are available to the C# programmer: FileInfo and File. Both classes belong to the namespace System.IO. Objects of class FileInfo represents a single file, created on the basis of the name or path of the file (which is a string). The class File contains static methods for file manipulation. Class File is static, see Section 11.12, and as such there can be no instances of class File. If you intend to write object-oriented programs with file manipulation needs it is recommended that you represent files as instances of class FileInfo.

Let us right away write a program which illustrates how to use instances of class FileInfo for representation of files. All aspects related to class FileInfo is shown in purple in Program 38.1.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52

using System;
using System.IO;

public class FileInfoDemo{

public static void Main(){
// Setting up file names
string fileName = "file-info.cs",
fileNameCopy = "file-info-copy.cs";

// Testing file existence
FileInfo fi = new FileInfo(fileName); // this source file
Console.WriteLine("{0} does {1} exist",
fileName, fi.Exists ? "" : "not");

// Show file info properties:
Console.WriteLine("DirectoryName: {0}", fi.DirectoryName);
Console.WriteLine("FullName: {0}", fi.FullName);
Console.WriteLine("Extension: {0}", fi.Extension);
Console.WriteLine("Name: {0}", fi.Name);
Console.WriteLine("Length: {0}", fi.Length);
Console.WriteLine("CreationTime: {0}", fi.CreationTime);

// Copy one file to another
fi.CopyTo(fileNameCopy);
FileInfo fiCopy  = new FileInfo(fileNameCopy);

// Does the copy exist?
Console.WriteLine("{0} does {1} exist",
fileNameCopy, fiCopy.Exists ? "" : "not");

// Delete the copy again
fiCopy.Delete();

// Does the copy exist?
Console.WriteLine("{0} does {1} exist",
fileNameCopy, fiCopy.Exists ? "" : "not"); // !!??

// Create new FileInfo object for the copy
FileInfo fiCopy1  = new FileInfo(fileNameCopy);
// Check if the copy exists?
Console.WriteLine("{0} does {1} exist", fileNameCopy,
fiCopy1.Exists ? "" : "not");

// Achieve a TextReader (StreamReader) from the file info object
// and echo the first ten lines in the file to standard output
using(StreamReader sr = fi.OpenText()){
for (int i = 1; i <= 10; i++)
Console.WriteLine("  " + sr.ReadLine());
}
}
}
 Program 38.1    A demonstration of the FileInfo class.

In line 12 we create a FileInfo object on the source file of the C# program text shown in Program 38.1. In line 13-14 we report on the existence of this file in the file system. (We expect existence, of course). In line 16-22 we access various properties (in the sense of C# properties, see Chapter 18) of the FileInfo object. In line 25 we copy the file, and in line 30 we check the existence of the copy. In line 33 we delete the copy, and in line 37 we check the existence of copy again. Against our intuition, we realize that the copy of the file still exists after its deletion. (See next paragraph for an explanation). If, however, we establish a fresh FileInfo object on the path to the deleted file, we get the expected result. In line 45-50 we use the OpenText method of the FileInfo object to establish a TextReader on the file. Via a number of ReadLine activations in line 49 we demonstrate that we can read the contents of the file.

The file existence problem described above occurs because the instance of class FileInfo and the state of the underlying file system become inconsistent. The instance method Refresh of class FileInfo can be used to update the FileInfo object from the information in the operating system. If you need trustworthy information about your files, you should always call the Refresh operation before you access any FileInfo attribute. If we call fiCopy.Refresh() in line 34, the problem observed in line 37 vanishes.

The output of Program 38.1 is shown in Listing 38.2 (only on web).

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

file-info.cs does  exist
DirectoryName: c:\users\kurt\courses\prog1-06\sources\c-sharp\io\file-info-demo
FullName: c:\users\kurt\courses\prog1-06\sources\c-sharp\io\file-info-demo\file-info.cs
Extension: .cs
Name: file-info.cs
Length: 1342
CreationTime: 02-11-2006 21:18:31
file-info-copy.cs does  exist
file-info-copy.cs does  exist
file-info-copy.cs does not exist
using System;
using System.IO;

public class FileInfoDemo{

public static void Main(){
string fileName = "file-info.cs",
fileNameCopy = "file-info-copy.cs";

FileInfo fi = new FileInfo(fileName); // this source file
 Listing 38.2    Output from the FileInfo demo program.

The following gives an overview of some selected operations in class FileInfo:

 A single constructorFileInfo(string)Properties (getters) that access information about the current fileExamples: Length, Extension, Directory, Exists, LastAccessTimeStream, reader, and writer factory methods:Examples: Create, AppendText, CreateText, Open, OpenRead, OpenWrite, OpenTextClassical file manipulationsCopyTo, Delete, MoveTo, ReplaceOthersRefresh, ...

The parameter of the FileInfo constructor is an absolute or relative path to a file. The file path must be well-formed according to a set of rules described in the class documentation. As examples, the file paths "c:\temp c:\user" and " dir1\dir2\file.dat" are both malformed.

We have also written af version of Program 38.1 in which we use the static class File instead of FileInfo, see Program 38.3. We do not include this program, nor the listing of its output, in the paper edition of the material. We notice that the file existence frustrations in Program 38.1 (of the deleted file) do not appear when we use the static operations of the static class File.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40

using System;
using System.IO;

public class FileDemo{

public static void Main(){

// Setup file names
string fileName = "file.cs",             // this source file
fileNameCopy = "fileCopy.cs";

// Does this source file exist?
Console.WriteLine("{0} does {1} exist",
fileName, File.Exists(fileName) ? "" : "not");

// Copy this source file
File.Copy(fileName, fileNameCopy);

// Does the copy exist?
Console.WriteLine("{0} does {1} exist",
fileNameCopy,
File.Exists(fileNameCopy) ? "" : "not");

// Delete the copy again
Console.WriteLine("Deleting {0}", fileNameCopy);
File.Delete(fileNameCopy);

// Does the deleted file exist
Console.WriteLine("{0} does {1} exist",
fileNameCopy,
File.Exists(fileNameCopy) ? "" : "not");

// Read all lines in source file and echo
// one of them to the console
string[] lines = File.ReadAllLines(fileName);
Console.WriteLine("Line {0}: {1}", 6, lines[6]);

}

}
 Program 38.3    A demonstration of the File class.

1
2
3
4
5

file.cs does  exist
fileCopy.cs does  exist
Deleting fileCopy.cs
fileCopy.cs does not exist
Line 6:     string fileName = "file.cs",             // this source file
 Listing 38.4    Output from the File demo program.

 There is a substantial overlap between the instance methods of class FileInfo and the static methods in class File

38.2.  The Directory and DirectoryInfo classes
Contents   Up Previous Next   Slide Annotated slide Aggregated slides    Subject index Program index Exercise index

The classes DirectoryInfo and Directory are natural directory counterparts of the classes FileInfo and File, as described in Section 38.1. In this section we will show an example use of class DirectoryInfo, and we will provide an overview of the members in the class. Like for files, an instance of class DirectoryInfo is intended to represent a given directory of the underlying file system. We recommend that you use the class DirectoryInfo, rather than the static class Directory, when you write object-oriented programs.

It is worth noticing that the classes FileInfo and DirectoryInfo have a common abstract, superclass class FileSystemInfo.

Here follows a short program that use an instance of class DirectoryInfo for representation of a given directory from the underlying operating system.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28

using System;
using System.IO;

public class DirectoryInfoDemo{

public static void Main(){
string fileName = "directory-info.cs";    // The current source file

// Get the DirectoryInfo of the current directory
// from the FileInfo of the current source file
FileInfo fi = new FileInfo(fileName);     // This source file
DirectoryInfo di = fi.Directory;

Console.WriteLine("File {0} is in directory \n   {1}", fi, di);

// Get the files and directories in the parent directory.
FileInfo[] files = di.Parent.GetFiles();
DirectoryInfo[] dirs = di.Parent.GetDirectories();

// Show the name of files and directories on the console
Console.WriteLine("\nListing directory {0}:", di.Parent.Name);
foreach(DirectoryInfo d in dirs)
Console.WriteLine(d.Name);
foreach(FileInfo f in files)
Console.WriteLine(f.Name);

}
}
 Program 38.5    A demonstration of the DirectoryInfo class.

Like in Program 38.3 the starting point in Program 38.5 is a FileInfo object that represents the source file shown in Program 38.5. Based on the FileInfo object, we create a DirectoryInfo object in line 12. This DirectoryInfo object represents the directory in which the actual source file resides. Let us call it the current directory . In line 17 we illustrate the Parent property and the GetFiles method; We create an array, files, of FileInfo object of the parent directory of the current directory. Thus, this array holds all files of the parent of current directory. Similarly, dirs declared in line 18 is assigned to hold all directories of the parent of current directory. We print these files and directories in line 20-25.

The output of Program 38.5 (only on web) is shown in Listing 38.6 (only on web). A similar program, programmed with use of the static operations in class Directory, is shown in Program 38.7 (only on web).

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

File directory-info.cs is in directory
C:\users\kurt\courses\prog1-06\sources\c-sharp\io\directory-info-demo

Listing directory io:
console
decorator
directory-info-demo
encoding
file-copy
file-demo
file-info-demo
filestream-ex
guess-encoding
README
 Listing 38.6    Output from the DirectoryInfo demo program.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28

using System;
using System.IO;

public class DirectoryDemo{

public static void Main(){
string fileName = "directory.cs";       // The current source file
FileInfo fi = new FileInfo(fileName);   // This source file

string thisFile =  fi.FullName,
thisDir =   Directory.GetParent(thisFile).FullName,
parentDir = Directory.GetParent(thisDir).FullName;

Console.WriteLine("This file: {0}", thisFile);
Console.WriteLine("This Directory: {0}", thisDir);
Console.WriteLine("Parent directory: {0}", parentDir);

string[] files = Directory.GetFiles(parentDir);
string[] dirs =  Directory.GetDirectories(parentDir);

Console.WriteLine("\nListing directory {0}:", parentDir);
foreach(string d in dirs)
Console.WriteLine(d);
foreach(string f in files)
Console.WriteLine(f);

}
}
 Program 38.7    A demonstration of the Directory class - similar to the DirectoryInfo demo program.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

This file: C:\users\kurt\courses\prog1-06\sources\c-sharp\io\directory-demo\directory.cs
This Directory: C:\users\kurt\courses\prog1-06\sources\c-sharp\io\directory-demo
Parent directory: C:\users\kurt\courses\prog1-06\sources\c-sharp\io

Listing directory C:\users\kurt\courses\prog1-06\sources\c-sharp\io:
C:\users\kurt\courses\prog1-06\sources\c-sharp\io\console
C:\users\kurt\courses\prog1-06\sources\c-sharp\io\decorator
C:\users\kurt\courses\prog1-06\sources\c-sharp\io\directory-demo
C:\users\kurt\courses\prog1-06\sources\c-sharp\io\directory-info-demo
C:\users\kurt\courses\prog1-06\sources\c-sharp\io\encoding
C:\users\kurt\courses\prog1-06\sources\c-sharp\io\file-copy
C:\users\kurt\courses\prog1-06\sources\c-sharp\io\file-demo
C:\users\kurt\courses\prog1-06\sources\c-sharp\io\file-info-demo
C:\users\kurt\courses\prog1-06\sources\c-sharp\io\filestream-ex
C:\users\kurt\courses\prog1-06\sources\c-sharp\io\guess-encoding
C:\users\kurt\courses\prog1-06\sources\c-sharp\io\README
 Listing 38.8    Output from the Directory demo program.

The following shows an overview of the instance properties and instance methods in class DirectoryInfo:

 A single constructorDirectoryInfo(string)Properties (getters) that access information about the current directoryExamples: CreationTime, LastAccessTime, Exists, Name, FullNameDirectory Navigation operationsUp: Parent, RootDown: GetDirectories, GetFiles, GetFileSystemInfo (all overloaded)Classical directory manipulationsCreate, MoveTo, DeleteOthersRefresh, ...

The constructor takes a directory path string as parameter. It is possible to create a DirectoryInfo object on a string that represents a non-existing directory path. Like file paths, the given directory path must be well-formed (according to rules stated in the class documentation).

The downwards directory navigation operations GetDirectories, GetFiles, and GetFileSystemInfo are able to filter their results (with use of strings with wildcards, such as "temp*", which match all files/directories whose names start with "temp"). It is also possible to specify if the operations should access direct files/directories, or if they should access direct as well as indirect file/directories.

 As for File and FileInfo, there is substantial overlap between the classes Directory and DirectoryInfo

 Generated: Monday February 7, 2011, 12:20:04