Playing With File I/O Using C#

In this article, you will learn about the basics of File I/O using C#. We are going to discuss the 3 classes - Path, Directory & File - to work with the file-system.

Introduction

 
Basic manipulation and navigating files & directories within the Windows Operating System which uses the “File Explorer” is really quite easy for most users. However; in some instances, file management could be an important part of an enterprise application. As a result, the Microsoft .NET framework provides a significant class-libraries inside System.IO namespace for file handling. Which returns the favor to developers, to do certain basic and advanced manipulation of files and directories.
 
If you are a newbie and need to somehow learn: how to handle and manage some file/directory manipulation within his/her application, this article is made just for you. However; those who are more advanced developers and/or readers are also welcome.
 
Let’s get started then.
 
In this article, we are going to explore the following classes: System.IO.Path, System.IO.Directory & System.IO.DirectoryInfo, System.IO.File  to see the features it has to offer. See our objectives below.
 

Objectives

  • Using the Path class to deal with filenames, directories, and paths to manage file-extensions, temporary files, temporary path, directory-name, and file-name, etc.
  • Using the Directory and DirectoryInfo classes to manipulate directories (create and delete) and add a directory to a certain access-rule.
  • Using the File class to deal with read and write to file.

Project Structure

 
The following classes, Explore_File_IO_Path.cs, Explore_File_IO_Directory.cs, Explore_File_IO_File.cs are unit test classes. The objective of these unit tests is basically to test the methods that we are going to tackle and study. Moreover; there’s one common thing about these classes, they have an Initialize method which literally initializes the projectPathLocation to get the directory of the running project. See the source code below.
  1. string projectPathLocation = string.Empty;  
  2.   
  3. [TestInitialize]  
  4. public void Initialize()  
  5. {  
  6.    projectPathLocation = AppConfig.ProjectPathLocation;  
  7. }  
The AppConfig.cs file acts as a configuration-class to get those project paths and directory structure in mind. See the source code below.
  1. public static class AppConfig  
  2. {   
  3.    public const string ProjectFiles = "project-files";  
  4.          
  5.    public static string[] ProjectDirectories = new string[]  
  6.    {  
  7.       "App-Data-1",  
  8.       "App-Data-2",  
  9.       "App-Data-3"  
  10.     };  
  11.           
  12.    public static Dictionary<stringstring[]> projectDirectoriesWithChild = new Dictionary<stringstring[]>   
  13.    {  
  14.       { "Directory-1"
  15.          new string[] { "A""B""C""D""E" }},  
  16.       { "Directory-2"
  17.          new string[] { "A""B""C""D""E",  }},  
  18.       { "Directory-3"
  19.          new string[] { "A""B""C""D""E",  }},  
  20.       { "Directory-4"
  21.          new string[] { "A""B""C""D""E",  }}       
  22.    };  
  23.           
  24.    public static string ProjectPathLocation          
  25.    {  
  26.       get { return Assembly.GetExecutingAssembly().Location; }      
  27.    }  
  28. }      
Lastly, to further visualize, see figure 1 for the project structure. The entire project can also be downloaded here.
 
Playing With File I/O Using C#
Figure 1
 

Explore and Play with System.IO.Path

 
Path class, it is a static class which provides common operations on dealing with filenames, directories, and paths. It is commonly known on String instances that contain files and/or directory path information. See figure 2 below to visualize the System.IO.Path static class and the methods it provides.
 
Playing With File I/O Using C#
Figure 2
 
Let us see the examples below.
 
In the example below, we have tried to explore the methods HasExtension and GetExtension which is straightforward.
  1. [TestMethod]  
  2. [Priority(1)]  
  3.  public void Test_PathLocation_If_Has_FileExtension_And_CheckExtension()  
  4.  {  
  5.    //true because the path has a file extension  
  6.    Assert.IsTrue(Path.HasExtension(projectPathLocation));  
  7.               
  8.    //gets the file extension  
  9.    string projectFileExtension = 
  10.    Path.GetExtension(projectPathLocation);  
  11.               
  12.    //true because the file extension of the assembly is .dll  
  13.    Assert.IsTrue(projectFileExtension == ".dll");   
  14.  }  
In the example below, we have tried to explore the method GetFilenameWithOutExtension. This method is really helpful when you only care about the filename only.
  1. [TestMethod]  
  2. [Priority(2)]  
  3. public void Test_Path_Method_GetFileName_Wihout_Extension()  
  4. {             
  5.    //try to get the file-name only forget about the extension          
  6.    string fileName = 
  7.    Path.GetFileNameWithoutExtension(projectPathLocation);  
  8.    
  9.    //true
  10.    Assert.AreEqual(fileName, "Playing_With_File_IO_Csharp");   
  11.  }  
In the example below, we have tried to explore the method Combine and ChangeExtension. As you can see we can combine different paths which will give us the full-string-path. And if you are interested to change the file extension of a file, you could use ChangeExtension.
  1. [TestMethod]  
  2. [Priority(3)]  
  3.        
  4. public void Test_Path_Method_GetFile_Then_Change_FileExtension()         
  5. {  
  6.    //pattern to verify file extension
  7.    string pattern = @"([^\\]+)\.{0}$"  
  8.    
  9.    //file-type extension        
  10.    string[] fileExtensions = new string[] { "txt""docx" };   
  11.      
  12.    string fullPath = 
  13.    Path.Combine(projectPathLocation, 
  14.                 "Playing_With_File_IO_Csharp.txt");  
  15.        
  16.    //true
  17.    Assert.IsTrue(Regex.IsMatch(fullPath, 
  18.       string.Format(pattern, fileExtensions[0])));   
  19.    
  20.    string changedPath = Path.ChangeExtension(fullPath, ".docx");  
  21.    
  22.    //true
  23.    Assert.IsTrue(Regex.IsMatch(changedPath, 
  24.       string.Format(pattern, fileExtensions[1])));   
  25. }  
In the last example below, we have tried to explore the methods GetTempPath, GetTempFileName which is really helpful for developers when dealing with temporary files. If we have an application that deals with temporary files and dump those files to temp-path, these two methods are very handy. 
  1. [TestMethod]  
  2. [Priority(4)]  
  3. public void Test_Path_Method_GetTempFilePath_And_CreateTemporaryFile()  
  4. {  
  5.     //gives you the location for the temporary folder  
  6.     string temporaryPath = System.IO.Path.GetTempPath();  
  7.   
  8.     //lets just check if the temporary path do exists  
  9.     Assert.IsTrue(Directory.Exists(temporaryPath));  
  10.   
  11.     //lets create a new (*.tmp) temporary file on disk  
  12.     string tempFileName = System.IO.Path.GetTempFileName();  
  13.   
  14.     //lets check if the temporary file exists  
  15.     Assert.IsTrue(File.Exists(tempFileName));   
  16. }  

Explore and Play with System.IO.Directory

 
Directory class is a static class which provides a lot of methods for dealing with directories. It exposes a lot of methods for creating, enumerating directories and subdirectories. However; I can’t discuss everything but will try to explore some. See figure 3 to visualize the System.IO.Directory static class and the methods it provides.
 
Playing With File I/O Using C#
Figure 3
 
Let us see the examples below.
 
In the example below, we have shown how to create a new directory using the CreateDirectorymethod. Upon successfully creating a directory the method CreateDirectory returns a DirectoryInfoclass which you can use to get information about the directory, sub-directories, and files.
  1. [TestMethod]  
  2.  [Priority(1)]  
  3.  public void Test_ProjectPath_Create_Directory()  
  4.  {  
  5.      //get the directory-name  
  6.      string directoryName = Path.GetDirectoryName(projectPathLocation);  
  7.   
  8.      //App-Data-1 as our directory-name  
  9.      string directoryToCreate = AppConfig.ProjectDirectories[0];  
  10.   
  11.      //uses the Path class to combine the two string to create a full path  
  12.      string fullPath = Path.Combine(directoryName, 
  13.                                  directoryToCreate);  
  14.   
  15.      //check whether is exists  
  16.      bool exists = Directory.Exists(fullPath);  
  17.   
  18.      if (!exists)  
  19.      {  
  20.          //Create a new directory  
  21.          var result = Directory.CreateDirectory(fullPath);  
  22.   
  23.          //verifies if not null   
  24.          Assert.IsNotNull(result);  
  25.   
  26.          //verifies if the instance type is DirectoryInfo  
  27.          Assert.IsInstanceOfType(result, typeof(DirectoryInfo));  
  28.      }  
  29.  }  
The example below, shows how to delete a directory using the Delete method. Straight-forward in my opinion and after successfully deleting the directory, it checks whether the directory still exists using the Exists method.
  1. [TestMethod]  
  2. [Priority(2)]  
  3. public void Test_ProjectPath_Delete_Directory()  
  4.    string directoryName = 
  5.             Path.GetDirectoryName(projectPathLocation);  
  6.     
  7.    string directoryToCreate = 
  8.             AppConfig.ProjectDirectories[0];
  9.    
  10.    string fullPath = 
  11.          Path.Combine(directoryName, directoryToCreate);  
  12.   
  13.    bool exists = Directory.Exists(fullPath);  
  14.           
  15.    if (exists)  
  16.    {                 
  17.       Directory.Delete(fullPath);  
  18.   
  19.       Assert.IsFalse(Directory.Exists(fullPath));  
  20.    }  
  21. }  
Let us show more examples on how to create/delete a directory with sub-directories. See the examples below.
  1. [TestMethod]  
  2. [Priority(3)]  
  3. public void Test_ProjectPath_Create_Multiple_Directories_With_SubDirectories()  
  4. {  
  5.     string directoryName = 
  6.             Path.GetDirectoryName(projectPathLocation);  
  7.   
  8.     foreach (var item in AppConfig.projectDirectoriesWithChild)  
  9.     {  
  10.         foreach (var child in item.Value)  
  11.         {  
  12.             string fullPath = 
  13.             Path.Combine(directoryName, item.Key, child);  
  14.   
  15.             var result = Directory.CreateDirectory(fullPath);  
  16.   
  17.             Assert.IsNotNull(result);  
  18.             Assert.IsInstanceOfType(result, typeof(DirectoryInfo));  
  19.         }  
  20.     }  
  21. }  
  22.   
  23. [TestMethod]  
  24. [Priority(4)]  
  25. public void Test_Project_Delete_Directory_Including_SubDirectories()  
  26. {  
  27.     string directoryName = 
  28.             Path.GetDirectoryName(projectPathLocation);  
  29.   
  30.     foreach (var item in AppConfig.projectDirectoriesWithChild)  
  31.     {  
  32.         string fullPath = Path.Combine(directoryName, item.Key);  
  33.   
  34.         var childDirectories = Directory.GetDirectories(fullPath);  
  35.   
  36.         Assert.IsTrue(childDirectories.Length > 0);  
  37.   
  38.         if (childDirectories.Length > 0)  
  39.         {  
  40.             Directory.Delete(fullPath, true);  
  41.         }  
  42.   
  43.         Assert.IsFalse(Directory.Exists(fullPath));  
  44.     }  
  45. }  
Now we have seen examples on creating and deleting directories and subdirectories. Let us try to create a directory with a DirectorySecurity class/object as passed argument to DirectoryInfo using the method SetAccessControl
  1. [TestMethod]  
  2. [Priority(5)]  
  3. public void Test_Create_Directory_With_Directory_Security()  
  4. {  
  5.     string directoryName = Path.GetDirectoryName(projectPathLocation);  
  6.   
  7.     foreach (var item in AppConfig.projectDirectoriesWithChild)  
  8.     {  
  9.         foreach (var child in item.Value)  
  10.         {  
  11.             string fullPath = Path.Combine(directoryName, item.Key, child);  
  12.   
  13.             if (!Directory.Exists(fullPath))  
  14.             {  
  15.                 DirectoryInfo directoryInfo = 
  16.                               Directory.CreateDirectory(fullPath);  
  17.   
  18.                 Assert.IsNotNull(directoryInfo);  
  19.                 Assert.IsInstanceOfType(directoryInfo, 
  20.                                          typeof(DirectoryInfo));  
  21.   
  22.                 DirectorySecurity directorySecurity = 
  23.                                    new DirectorySecurity();  
  24.   
  25.                 directorySecurity.AddAccessRule(
  26.                      new FileSystemAccessRule("Power Users"
  27.                          FileSystemRights.FullControl, AccessControlType.Allow));  
  28.                 
  29.                   directorySecurity.AddAccessRule(
  30.                      new FileSystemAccessRule("Guests"
  31.                      FileSystemRights.Delete, AccessControlType.Deny));  
  32.   
  33.                 directoryInfo.SetAccessControl(directorySecurity);  
  34.             }  
  35.         }  
  36.     }  
  37. }  

Explore and Play with System.IO.File

 
File class is a static class which provides a lot of methods for dealing with files. It exposes methods for creating, copying, deleting, moving, etc. for a single file. See figure 4 to visualize the System.IO.File static class and the methods it provides.
 
Playing With File I/O Using C#
Figure 4
 
In this last section, we are going to focus on the read and write to file, focusing on 3 methods WriteAllText, WriteAllLines, and ReadAllLines. To further prove the sample code, I decided to compare the content that was set on the file and verify if we have the same content after calling the method ReadAllLines. Let us see the examples below.
  1. string projectPathLocation = string.Empty;  
  2.   
  3.         string projectFile_FullPath = string.Empty;  
  4.   
  5.         [TestInitialize]  
  6.         public void Initialize()  
  7.         {  
  8.             projectPathLocation = AppConfig.ProjectPathLocation;  
  9.   
  10.             projectFile_FullPath = Path.Combine(Path.GetDirectoryName(projectPathLocation), "project-files");  
  11.         }  
  12.   
  13.         [TestMethod]  
  14.         public void Test_File_WriteAllText_And_ReadContent_Then_Compare_If_Equal()  
  15.         {  
  16.   
  17.             //let's create a simple content  
  18.             StringBuilder content = new StringBuilder();  
  19.   
  20.             content.AppendLine("Hello System.IO.File");  
  21.   
  22.             content.AppendLine("File class");  
  23.   
  24.             //convert the StringBuilder to String  
  25.             string fullContent = content.ToString();  
  26.   
  27.             //get the filename  
  28.             string fullPathToFile = 
  29.             Path.Combine(projectFile_FullPath, "Playing_With_File_IO_Csharp_1.txt");  
  30.   
  31.             //set to empty first the file  
  32.             File.WriteAllText(fullPathToFile, string.Empty, Encoding.UTF8);  
  33.   
  34.             //put the content on the file  
  35.             File.WriteAllText(fullPathToFile, fullContent, Encoding.UTF8);  
  36.   
  37.             //let us read the content the file  
  38.             string[] fileContent = File.ReadAllLines(fullPathToFile, Encoding.UTF8);  
  39.   
  40.             //compare the file content to the one we declared  
  41.             Assert.AreEqual(string.Compare(fullContent, 
  42.                   string.Format("{0}{1}"
  43.                   string.Join(Environment.NewLine, fileContent), 
  44.                    Environment.NewLine)), 0);  
  45.   
  46.         }  
  47.   
  48.         [TestMethod]  
  49.         public void Test_File_WriteAllLines_And_ReadContent_Then_Compare_If_Equal_Using_Array()  
  50.         {  
  51.             string[] fileContents = new string[] 
  52.             { "Hello""World""File""Class"
  53.                "Welcome""To""The""World"
  54.                "Of""System.IO" };  
  55.   
  56.             string fullPathToFile = 
  57.                    Path.Combine(projectFile_FullPath, "Playing_With_File_IO_Csharp_2.txt");  
  58.   
  59.             File.WriteAllText(fullPathToFile, string.Empty, Encoding.UTF8);  
  60.   
  61.             File.WriteAllLines(fullPathToFile, fileContents, Encoding.UTF8);  
  62.   
  63.             //let us read the content the file  
  64.             string[] readFileContents = 
  65.                       File.ReadAllLines(fullPathToFile, Encoding.UTF8);  
  66.   
  67.             //compare the file content to the one we declared  
  68.             var result = Enumerable.SequenceEqual(fileContents, readFileContents);  
  69.               
  70.             //true  
  71.             Assert.IsTrue(result);  
  72.         }  

Summary

 
In this article, I’ve discussed the Path, Directory and File static classes inside the System.IO namespace. We have seen and explored some exposed methods by creating and deleting directories and subdirectories; by manipulating strings via Path class; and lastly, by writing and reading to a file using the File static class. I’m hoping you have enjoyed it and until next time, happy programming!