File Handling in C# .NET

Abstract

This article illustrates how to perform tasks involving reading and writing files from various partitions using the C# .Net programming API. In particular, it covers exploring the directory structure, determining what files and folders are present and also does other file-related operations such as moving, copying and deleting objects from the disk. The core purpose of this article is to explorer types defined in the System.IO namespace and to provide an understanding of various ways to read from and write to character based, binary based and string based data stores.

The Anatomy of the File System

The System.IO namespace provides four classes that allow you to manipulate individual files, as well as interact with a machine directory structure. The Directory and File directly extends System.Object and supports the creation, copying, moving and deletion of files using various static methods. They only contain static methods and are never instantiated. The FileInfo and DirecotryInfo types are derived from the abstract class FileSystemInfo type and they are typically, employed for obtaining the full details of a file or directory because their members tend to return strongly typed objects. They implement roughly the same public methods as a Directory and a File but they are stateful and the members of these classes are not static.

File System

In the .NET framework, the System.IO namespace is the region of the base class libraries devoted to file based input and output services. Like any namespace, the System.IO namespace defines a set of classes, interfaces, enumerations, structures and delegates. The following table outlines the core members of this namespace:

Class Types

Description

Directory/ DirectoryInfo

These classes support the manipulation of the system directory structure.

DriveInfo

This class provides detailed information regarding the drives that a given machine has.

FileStream

This gets you random file access with data represented as a stream of bytes.

File/FileInfo

These sets of classes manipulate a computer's files.

Path

It performs operations on System.String types that contain file or directory path information in a platform-neutral manner.

BinaryReader/ BinaryWriter

These classes allow you to store and retrieve primitive data types as binary values.

StreamReader/StreamWriter

Used to store textual information to a file.

StringReader/StringWriter

These classes also work with textual information. However, the underlying storage is a string buffer rather than a physical file.

BufferedStream

This class provides temp storage for a stream of bytes that you can commit to storage at a later time.

The System.IO provides a class DriveInfo to manipulate the system drive related tasks. The DriveInfo class provides numerous details such as the total number of drives, calculation of total hard disk space, available space, drive name, ready status, types and so on. Consider the following program that shows the total disk drives:

  1. DriveInfo[] di = DriveInfo.GetDrives();  
  2. Console.WriteLine("Total Partitions");  
  3.   
  4. foreach(DriveInfo items in di)  
  5. {  
  6.    Console.WriteLine(items.Name);  
  7. }  
The following code snippets perform the rest of the DriveInfo class method operations in details. It displays specific drive full information.
  1. using System;  
  2. using System.IO;  
  3.   
  4. namespace DiskPartition  
  5. {  
  6.     class Program  
  7.     {  
  8.         static void Main(string[] args)  
  9.         {  
  10.             DriveInfo[] di = DriveInfo.GetDrives();  
  11.   
  12.             Console.WriteLine("Total Partitions");  
  13.             Console.WriteLine("---------------------");    
  14.             foreach(DriveInfo items in di)  
  15.             {  
  16.                 Console.WriteLine(items.Name);    
  17.             }  
  18.             Console.Write("\nEnter the Partition::");  
  19.             string ch = Console.ReadLine();  
  20.   
  21.             DriveInfo dInfo = new DriveInfo(ch);  
  22.   
  23.             Console.WriteLine("\n");  
  24.   
  25.             Console.WriteLine("Drive Name::{0}",dInfo.Name);  
  26.             Console.WriteLine("Total Space::{0}", dInfo.TotalSize);  
  27.             Console.WriteLine("Free Space::{0}", dInfo.TotalFreeSpace);  
  28.             Console.WriteLine("Drive Format::{0}", dInfo.DriveFormat);  
  29.             Console.WriteLine("Volume Label::{0}", dInfo.VolumeLabel);  
  30.             Console.WriteLine("Drive Type::{0}", dInfo.DriveType);  
  31.             Console.WriteLine("Root dir::{0}", dInfo.RootDirectory);  
  32.             Console.WriteLine("Ready::{0}", dInfo.IsReady);  
  33.               
  34.             Console.ReadKey();   
  35.         }  
  36.     }  
  37. }  
After compiling this program, it displays nearly every detail of disk drives and a specific drive as in the following:

drive

Working with Directories

The .NET framework provides the two rudimentary classes, DirectoryInfo and Directory, to do directory-related operations such as creation and deletion.

    DirectoryInfo Class

    The DirectoryInfo class contains a set of members for the creation, deletion, moving and enumeration over directories and subdirectories. Here, in the following code sample, display the information related to temp directory.

    1. DirectoryInfo di=new DirectoryInfo(@"D:\temp");   
    2.   
    3. Console.WriteLine("*******Direcotry Informations*******\n\n");  
    4. Console.WriteLine("Full Name={0}",di.FullName);  
    5. Console.WriteLine("Root={0}",di.Root);  
    6. Console.WriteLine("Attributes={0}", di.Attributes);  
    7. Console.WriteLine("Creation Time={0}", di.CreationTime);  
    8. Console.WriteLine("Name={0}", di.Name);  
    9. Console.WriteLine("Parent={0}", di.Parent);  
    The previous code produces the information related to the temp directory located in the D drive as in the following:

    output

    Typically, we make the assumption that the path passed in the constructor of the DirectoryInfo class physically exists. However, if you attempt to interact with a nonexistent directory then the CLR will throw an exception. So, we need to create a directory first to handle the exceptions that occur as in the following.
    1. DirectoryInfo di=new DirectoryInfo(@"D:\temp\xyz");  
    2. di.Create();   
    We can also programmatically extends a directory structure using the CreateSubdirectory() method. The following code sample first creates a sub directory in D drive then in D:\ajay\ as in the following:
    1. DirectoryInfo di=new DirectoryInfo(@"D:\");  
    2. di.CreateSubdirectory("ajay");  
    3. di.CreateSubdirectory(@"ajay\ajay11");   
    Directory Class

    The Directory class provides nearly the same functionality as DirecotryInfo. The Directory class typically returns string data rather than strongly typed DirectoryInfo objects. The following sample deletes the directory and subdirectory in the D drive.
    1. static void Main(string[] args)  
    2. {  
    3.      DirectoryInfo di = new DirectoryInfo(@"d:\abc");  
    4.      Console.WriteLine("Name:{0}",di.FullName);  
    5.   
    6.      Console.Write("Are you sure to Delete:");  
    7.      string str=Console.ReadLine();  
    8.      if (str == "y")  
    9.      {  
    10.          Directory.Delete(@"d:\abc"true);  
    11.      }  
    12.      Console.Write("Deleted.....");  
    13. }
Reading and Writing to Files

Reading and writing operations are done using a File object. The following code snippet reads a text file located in the machine somewhere.
  1. private void button1_Click(object sender, EventArgs e)  
  2. {  
  3.     try  
  4.     {  
  5.         textBox2.Text = File.ReadAllText(txtPath.Text);  
  6.     }  
  7.     catch (FileNotFoundException)  
  8.     {  
  9.         MessageBox.Show("File not Found....");    
  10.     }  
  11. }  
Here, first the user interface asks the user to enter the path of the file that he wanted to display. Later that path is passed to the File method ReadAllText() method that reads all the text integrated in the file and displays it over the text box.

Besides reading a file, we can write some contents over an existing text file by the File class WriteAllTest() method as in the following:
  1. File.WriteAllText(@"d:\test.txt", textBox2.Text);  
It takes a path to save the file and content input method medium such as a text box or any other control. The following images depict a text file reading by entering its corresponding path:

corresponding path

Stream

The .NET provides many objects such as FileStream, StreamReader/Writer, BinaryReader/Writer to read from and write data to a file. A stream basically represents a chunk of data flowing between a source and a destination. Stream provides a common way to interact with a sequence of bytes regardless of what kind of devices store or display the bytes. The following table provides common stream member functions:

Methods

Description

Read()/ ReadByte()

Read a sequence of bytes from the current stream.

Write()/WriteByte()

Write a sequence of bytes to the current stream.

Seek()

Sets the position in the current stream.

Position()

Determine the current position in the current stream.

Length()

Return the length of the stream in bytes.

Flush()

Updates the underlying data source with the current state of the buffer and then clears the buffer.

Close()

Closes the current stream and releases any associated stream resources.

FileStream

A FileStream instance is used to read or write data to or from a file. In order to construct a FileStream, first we need a file that we want to access. Second, the mode that indicates how we want to open the file. Third, the access that indicates how we want to access a file. And finally, the share access that specifies whether you want exclusive access to the file.

Enumeration

Values

FileMode

Create, Append, Open, CreateNew, Truncate, OpenOrCreate

FileAccess

Read, Write, ReadWrite

FileShare

Inheritable, Read, None, Write, ReadWrite

The FileStream can read or write only a single byte or an array of bytes. You will be required to encode the System.String type into a corresponding byte array. The System.Text namespace defines a type named encoding that provides members that encode and decode strings to an array of bytes. Once encoded, the byte array is persisted to a file with the FileStream.Write() method. To read the bytes back into memory, you must reset the internal position of the stream and call the ReadByte() method. Finally, you display the raw byte array and the decoded string to the console.

  1. using(FileStream fs=new FileStream(@"d:\ajay123.doc",FileMode.Create))  
  2. {  
  3.     string msg = "first program";  
  4.     byte[] byteArray = Encoding.Default.GetBytes(msg);  
  5.     fs.Write(byteArray, 0, byteArray.Length);  
  6.     fs.Position = 0;  
  7.  
  8.     byte[] rFile = new byte[byteArray.Length];  
  9.  
  10.     for (int i = 0; i < byteArray.Length; i++)  
  11.     {  
  12.         rFile[i] = (byte)fs.ReadByte();  
  13.         Console.WriteLine(rFile[i]);    
  14.     }  
  15.   
  16.     Console.WriteLine(Encoding.Default.GetString(rFile));  
  17. }  
BinaryReader and BinaryWriter

The BinaryReader and Writer class allows you to read and write discrete data types to an underlying stream in a compact binary format. The BinaryWriter class defines a highly overloaded Write method to place a data type in the underlying stream.
 

Members

Description

Class

Write

Write the value to current stream

BinaryWriter

Seek

Set the position in the current stream

BinaryWriter

Close

Close the binary reader

BinaryWriter

Flush

Flush the binary stream

BinaryWriter

PeekChar

Return the next available character without advancing the position in the stream

BinaryReader

Read

Read a specified set of bytes or characters and store them in the incoming array.

BinaryReader

The following sample first writes a number of data contents to a new champu.dat file using BinaryWriter. Later, to read the data, the BinaryReader class employs a number of methods.

  1.  class Program  
  2.  {  
  3.      static void Main(string[] args)  
  4.      {  
  5.          // writing   
  6.          FileInfo fi = new FileInfo("champu.dat");  
  7.          using (BinaryWriter bw = new BinaryWriter(fi.OpenWrite()))  
  8.          {  
  9.              int x = 007;  
  10.              string str = "hello champu ,one day you will become doomkatu";  
  11.   
  12.              bw.Write(x);   
  13.              bw.Write(str);  
  14.          }  
  15.   
  16.          //Reading  
  17.          FileInfo f = new FileInfo("champu.dat");  
  18.          using (BinaryReader br = new BinaryReader(fi.OpenRead()))  
  19.          {  
  20.              Console.WriteLine(br.ReadInt32());  
  21.              Console.WriteLine(br.ReadString());  
  22.          }  
  23.          Console.ReadLine();  
  24.   
  25.      }  
  26.  }  
StringReader and StringWriter

We can use StringWriter and StringReader to treat textual information as a stream of in-memory characters. This can prove helpful when you wish to append character-based information to an underlying buffer. The following code sample illustrates this by writing a block of string data to a StringWriter object, rather than to a file on the local hard drive:
  1. static void Main(string[] args)  
  2. {  
  3.     // writing   
  4.     using (StringWriter sw = new StringWriter())  
  5.     {  
  6.         sw.WriteLine("helloooooooooooooooooooo");  
  7.           
  8.         // Reading  
  9.         using (StringReader sr = new StringReader(sw.ToString()))  
  10.         {  
  11.             string input = null;  
  12.             while((input = sr.ReadLine())!=null)  
  13.             {  
  14.                 Console.WriteLine(input);    
  15.             }  
  16.         }  
  17.     }     
  18.  }  
Summary

This article begins with an introduction to the .NET file system and its detailed class hierarchy. We have learned to manipulate a physical file or directory on your hard drive using the File and Directory classes. Next, we examined the Stream class in details. The System.IO namespace provides numerous writer and reader types, for instance FilStream, BinaryStream, StringStream and so on.. So, this article provides a full understanding to access data from a hard drive and writes them back.