Introduction to Basic File IO

Introduction to Basic File I/O

In the .NET Framework, file I/O is accomplished using streams. Although some classes may make certain aspects of reading and writing to text files easier, those classes still make use of streams for the final read and write operations on operating system files. This section shows you how to create, append to, read from, and query information about files. You will also see how the framework provides utility classes for common file operations, such as the StreamWriter class that is used in conjunction with the File class to make working with plain text files easy.

Creating and Appending Files

When working with files using the Stream pattern, the majority of the work is done in the constructor for the FileStream class. This constructor allows you to specify the filename (or a classic Win32 file handle), as well as access modes, sharing modes, and much more. Using the constructor, you indicate whether you want to create a new file or open an existing file, or open an existing file for appending.

The following few lines of code create a new file and write some text to it:

string origString =     "I never saw an author who was aware that there is any "+     "dimensional difference between a fact and a surmise.\n"+     " - Mark Twain"; // create the file, write to it, save it. FileStream fs = new FileStream("quote.txt", FileMode.Create); fs.Write(ASCIIEncoding.ASCII.GetBytes(origString),0,     origString.Length); fs.Close(); 

Note that you need to close the FileStream in order for the contents of the Stream to be written to disk. As mentioned in the description for the Stream class, the Close method releases all resources and flushes the remaining contents of the buffer to whatever underlying media backs the stream, such as a disk file.

You can use a different option in the constructor to obtain a FileStream for the same file, but this time you can use the Stream to append additional data to the file:

string addString =     "\n\nGood friends, good books and a sleepy conscience: "+     "this is the ideal life.\n" +     " - Mark Twain"; fs= new FileStream("quote.txt", FileMode.Append); fs.Write(ASCIIEncoding.ASCII.GetBytes(addString), 0, addString.Length); fs.Close(); 

The preceding code uses the FileMode.Append enumeration item to indicate how the file should be opened. Table 7.3 contains a description of each of the possible file modes.

Table 7.3. File Mode Enumeration Values

File Mode



Opens the file if it exists and seeks to the end of the file. If the file does not exist, a new file is created.


Creates a new file. If a file already exists with the indicated name, the file is overwritten.


Creates a new file. If the file already exists, an IOException error will be thrown.


Opens an existing file. A FileNotFoundException exception will be thrown if the file does not exist.


Opens an existing file. If the file does not exist, it will be created.


Opens an existing file. After the file is opened, its size will be reduced to 0 bytes and all data contained within it will be lost.

Now that you have seen the low-level way of creating basic files, whether they are binary files or text files, let's take a look at a quicker and easier way of working with text files.

You can replace the preceding code where you have to work with arrays of bytes with the following code, making the code easier to read and simpler to write:

StreamWriter sw = File.CreateText("quote2.txt"); sw.Write(origString); sw.Write(addString); sw.Close(); 

As you can see, the code is a lot simpler than the previous examples. The reason this chapter started off showing you how to work with arrays of bytes is that this knowledge will help you if you need to work with files that don't contain simple text, such as image files or binary files containing fixed data structures.

Reading from Existing Files

Reading from files using streams works just like all other I/O that has been discussed in this chapter up to this point. You obtain a reference to the file either using the FileStream class constructor or using the File class.

When you have a reference to the file from which you want to read, you can read that data using the stream's Read or ReadByte methods.

The following code uses a FileStream class to open an existing file, read an array of bytes from it, and display the resulting array of bytes as an ASCII string:

byte[] fileBytes = new byte[origString.Length + addString.Length]; fs = new FileStream("quote.txt", FileMode.Open); fs.Read(fileBytes, 0, (int)fs.Length); Console.WriteLine("Quote from the file:"); Console.WriteLine(ASCIIEncoding.ASCII.GetString(fileBytes)); 

And now take a look at the same effect using the OpenText method of the File class to create an instance of the StreamReader class:

StreamReader sr = File.OpenText("quote2.txt"); Console.WriteLine("Entire file: \n" + sr.ReadToEnd()); sr.Close(); 

Using Directories and the File System

In all the previous examples, the filename of the file with which we were working was known and fixed. This isn't exactly a good model of reality. In most commercial applications that deal with files, you need to do things like check to make sure that a file exists, or check to see if a specific directory exists. If the directory doesn't exist when you need to create the file, you need to create the directory as well.

To help developers deal with this, the System.IO namespace provides the following classes:

  • File A static class that provides methods for testing for the existence of a file, copying files, deleting files, moving files, as well as the opening of files and, as shown in the preceding example, the creation of streams from files.

  • FileInfo An instance class that provides information about a specific file. Also contains instance methods for performing copy, move, delete and related operations.

  • Directory Static class that provides methods for determining the existence of directories, creating directories, and much more.

  • DirectoryInfo Provides instance methods for operating on a specific directory, including renaming, obtaining the list of files within the directory, and so on.

  • Path A utility class for parsing and building path strings.

For more information on each of these individual classes, you can refer to the MSDN documentation online at The example in Listing 7.2 illustrates how to test and see if a file exists, and if it does, create a subdirectory, copy the file there, and then display some operating system-level information about the file itself.

Listing 7.2. File Manipulation and Query

using System; using System.Security; using System.Security.Principal; using System.Security.AccessControl; using System.IO; using System.Collections.Generic; using System.Text; namespace DirManip { class Program { static void Main(string[] args) {     if (File.Exists("quote.txt"))     {         if (!Directory.Exists("quotedir"))         {             Directory.CreateDirectory("quotedir");         }         FileInfo f = new FileInfo("quote.txt");         if (!File.Exists(@"quotedir\quote.txt"))             f.CopyTo(@"quotedir\quote.txt");         Console.WriteLine("File: " + f.FullName);         Console.WriteLine("Location: " + f.Directory.FullName);         Console.WriteLine("Created: " + f.CreationTime.ToShortDateString());         FileSecurity fs = f.GetAccessControl();         Console.WriteLine("Owner: {0}", fs.GetOwner(typeof(NTAccount)));         AuthorizationRuleCollection arc =             fs.GetAccessRules(true, true, typeof(NTAccount));         foreach (FileSystemAccessRule ar in arc)         {             Console.WriteLine(ar.ToString());             Console.WriteLine("User: {0}", ar.IdentityReference);             Console.WriteLine("Type: {0}", ar.AccessControlType);         }         Console.ReadLine();     } } } } 

The core of the code starts with the instantiation of a new FileInfo object, from which you can perform many different operations (such as a copy) as well as query detailed information about the file itself.

Developers who are familiar with file-level programming in previous versions of C# may start to get a little giddy when they notice that you can now obtain an ACL (Access Control List) starting with the FileInfo object. Previously, obtaining the list of access rights associated with a file was a painful and tedious task that involved invoking the Win32 API using a technique (discussed in Chapter 13, "COM and Windows Interoperability") called "Platform Invoke."

The output of the preceding code looks as follows:

File: D:\SAMS\C# Unleashed 2005\Chapters\07\Code\DirManip\DirManip\bin\Debug\quote.txt Location: D:\SAMS\C# Unleashed 2005\Chapters\07\Code\DirManip\DirManip\bin\Debug Created:11/7/2005 Owner: Everyone User: Everyone Type: Allow 

Microsoft Visual C# 2005 Unleashed
Microsoft Visual C# 2005 Unleashed
ISBN: 0672327767
EAN: 2147483647
Year: 2004
Pages: 298 © 2008-2017.
If you may any questions please contact us: