Patrick Smacchia [MVP C#]

Sponsors

The Lounge

Advertisement

Images in this post missing? We recently lost them in a site migration. We're working to restore these as you read this. Should you need an image in an emergency, please contact us at imagehelp@codebetter.com
A free library to handle common and complex path operations

I just release the library NDepend.Helpers.FilePathDirectory on CodePlex. 

NDepend.Helpers.FilePathDirectory is the library used by the tool NDepend to handle common path operations. Benefits of the NDepend.Helpers.FilePathDirectory over the .NET Framework class System.IO.Path include:

  • Strongly typed File/Directory path.
  • Relative / absolute path conversion.
  • Path normalization API
  • Path validity check API
  • Path comparison API
  • Path browsing API.
  • Path rebasing API
  • List of path operations (TryGetCommonRootDirectory, GetListOfUniqueDirsAndUniqueFileNames, list equality…)


NDepend.Helpers.FilePathDirectory is 100% unit-tested and tests code is provided with the source code.

Here is a simple class diagram of the object model:

 

 

Here is some code that shows common NDepend.Helpers.FilePathDirectory use cases:

using NDepend.Helpers.FileDirectoryPath;

using System.Diagnostics;

using System.Collections.Generic;

 

class Program {

   static void Main(string[] args) {

      FilePathAbsolute filePathAbsolute1, filePathAbsolute2;

      FilePathRelative filePathRelative1;

      DirectoryPathAbsolute directoryPathAbsolute1;

      DirectoryPathRelative directoryPathRelative1;

 

 

      //

      //  Path normalization

      //

      filePathAbsolute1 = new FilePathAbsolute(@"C:/Dir1\\File.txt");

      Debug.Assert(filePathAbsolute1.Path == @"C:\Dir1\File.txt");

 

      directoryPathAbsolute1 = new DirectoryPathAbsolute(@"C:/Dir1\\Dir2\");

      Debug.Assert(directoryPathAbsolute1.Path == @"C:\Dir1\Dir2");

 

      directoryPathAbsolute1 = new DirectoryPathAbsolute(@"C:\Dir1\..\Dir2\.");

      Debug.Assert(directoryPathAbsolute1.Path == @"C:\Dir2");

 

 

      //

      // Path comparison

      //

      filePathAbsolute1 = new FilePathAbsolute(@"C:/Dir1\\File.txt");

      filePathAbsolute2 = new FilePathAbsolute(@"C:\DIR1\FILE.TXT");

      Debug.Assert(filePathAbsolute1.Equals(filePathAbsolute2));

      Debug.Assert(filePathAbsolute1 == filePathAbsolute2);

 

 

      //

      // Relative -> Absolute path conversion

      //

      filePathRelative1 = new FilePathRelative(@"..\..\Dir1\File.txt");

      directoryPathAbsolute1 = new DirectoryPathAbsolute(@"C:\Dir2\Dir3\Dir4");

      filePathAbsolute1 = filePathRelative1.GetAbsolutePathFrom(directoryPathAbsolute1);

      Debug.Assert( filePathAbsolute1.Path == @"C:\Dir2\Dir1\File.txt");

 

 

      //

      // Absolute -> Relative path conversion

      //

      filePathAbsolute1 = new FilePathAbsolute(@"C:\Dir1\File.txt");

      directoryPathAbsolute1 = new DirectoryPathAbsolute(@"C:\Dir2\Dir3\Dir4");

      filePathRelative1 = filePathAbsolute1.GetPathRelativeFrom(directoryPathAbsolute1);

      Debug.Assert(filePathRelative1.Path == @"..\..\..\Dir1\File.txt");

 

 

      //

      // Path string validation

      //

      string reason;

      Debug.Assert(PathHelper.IsValidAbsolutePath(@"C:\Dir2\Dir1", out reason));

      Debug.Assert(!PathHelper.IsValidAbsolutePath(@"C:\..\Dir1", out reason));

      Debug.Assert(!PathHelper.IsValidAbsolutePath(@".\Dir1", out reason));

      Debug.Assert(!PathHelper.IsValidAbsolutePath(@"1:\Dir1", out reason));

      Debug.Assert(PathHelper.IsValidRelativePath(@".\Dir1\Dir2", out reason));

      Debug.Assert(PathHelper.IsValidRelativePath(@"..\Dir1\Dir2", out reason));

      Debug.Assert(PathHelper.IsValidRelativePath(@".\Dir1\..\Dir2", out reason));

      Debug.Assert(!PathHelper.IsValidRelativePath(@".\Dir1\..\..\Dir2", out reason));

      Debug.Assert(!PathHelper.IsValidRelativePath(@"C:\Dir1\Dir2", out reason));

 

 

      //

      // File name & extension

      //

      filePathAbsolute1 = new FilePathAbsolute(@"C:\Dir1\File.cs.Txt");

      Debug.Assert(filePathAbsolute1.FileName == "File.cs.Txt");

      Debug.Assert(filePathAbsolute1.FileNameWithoutExtension == "File.cs");

      Debug.Assert(filePathAbsolute1.FileExtension == ".Txt");

      Debug.Assert(filePathAbsolute1.HasExtension(".txt"));

 

 

      //

      // Path browsing

      //

      filePathAbsolute1 = new FilePathAbsolute(@"C:\Dir1\File.cs.Txt");

      Debug.Assert(filePathAbsolute1.ParentDirectoryPath.Path == @"C:\Dir1");

      Debug.Assert(filePathAbsolute1.GetBrotherFileWithName("File.xml").Path == @"C:\Dir1\File.xml");

      Debug.Assert(filePathAbsolute1.ParentDirectoryPath.GetChildDirectoryWithName("Dir2").Path == @"C:\Dir1\Dir2");

      Debug.Assert(filePathAbsolute1.ParentDirectoryPath.GetChildDirectoryWithName("..").Path == @"C:");

 

      directoryPathRelative1 = new DirectoryPathRelative(@"..\Dir1\Dir2");

      Debug.Assert(directoryPathRelative1.ParentDirectoryPath.Path == @"..\Dir1");

 

 

      //

      // Path rebasing

      //

      directoryPathAbsolute1 = new DirectoryPathAbsolute(@"C:\Dir1\Dir2\Dir3");

      DirectoryPathAbsolute directoryPathAbsolute2 = new DirectoryPathAbsolute(@"E:\Dir4\Dir1");

      DirectoryPathAbsolute rebasedPath;

      PathHelper.TryRebasePath(directoryPathAbsolute1, directoryPathAbsolute2, out rebasedPath);

      Debug.Assert(rebasedPath.Path == @"E:\Dir4\Dir1\Dir2\Dir3");

 

 

      //

      // List of path  ListOfPathsEquals \ Contains \ TryGetCommonRootDirectory

      //

      List<DirectoryPathAbsolute> list1 = new List<DirectoryPathAbsolute>();

      List<DirectoryPathAbsolute> list2 = new List<DirectoryPathAbsolute>();

      list1.Add(new DirectoryPathAbsolute(@"C:\Dir1\Dir2"));

      list2.Add(new DirectoryPathAbsolute(@"c:\dir1\dir2"));

      list1.Add(new DirectoryPathAbsolute(@"C:\Dir1\Dir3\Dir4"));

      list2.Add(new DirectoryPathAbsolute(@"c:\dir1\dir3\dir4"));

      Debug.Assert(ListOfPathHelper.ListOfPathsEquals(list1, list2));

      Debug.Assert(ListOfPathHelper.Contains(list1, new DirectoryPathAbsolute(@"C:\Dir1\dir2")));

      ListOfPathHelper.TryGetCommonRootDirectory(list1, out directoryPathAbsolute1);

      Debug.Assert(directoryPathAbsolute1.Path == @"C:\Dir1");

 

      //

      // List of path   GetListOfUniqueDirsAndUniqueFileNames

      //

      List<FilePathAbsolute> list = new List<FilePathAbsolute>();

      list.Add(new FilePathAbsolute(@"E:\Dir1\Dir2\File1.txt"));

      list.Add(new FilePathAbsolute(@"E:\dir1\dir2\File2.txt"));

      list.Add(new FilePathAbsolute(@"E:\Dir1\Dir2\Dir3\file2.txt"));

      List<DirectoryPathAbsolute> listOfUniqueDirs;

      List<string> listOfUniqueFileNames;

      ListOfPathHelper.GetListOfUniqueDirsAndUniqueFileNames(list, out listOfUniqueDirs, out listOfUniqueFileNames);

      Debug.Assert(listOfUniqueDirs.Count == 2);

      Debug.Assert(listOfUniqueDirs[0].Path == @"E:\Dir1\Dir2");

      Debug.Assert(listOfUniqueDirs[1].Path == @"E:\Dir1\Dir2\Dir3");

      Debug.Assert(listOfUniqueFileNames.Count == 2);

      Debug.Assert(listOfUniqueFileNames[0] == "File1.txt");

      Debug.Assert(listOfUniqueFileNames[1] == "File2.txt");

 

 

      //

      // Interaction with System.IO API

      //

      filePathAbsolute1 = new FilePathAbsolute(

         System.Reflection.Assembly.GetExecutingAssembly().Location);

      Debug.Assert(filePathAbsolute1.Exists);

      System.IO.FileInfo fileInfo = filePathAbsolute1.FileInfo;

 

      directoryPathAbsolute1 = filePathAbsolute1.ParentDirectoryPath as DirectoryPathAbsolute;

      Debug.Assert(directoryPathAbsolute1.Exists);

      System.IO.DirectoryInfo directoryInfo = directoryPathAbsolute1.DirectoryInfo;

 

      List<DirectoryPathAbsolute> listSubDir = directoryPathAbsolute1.ChildrenDirectoriesPath;

      List<FilePathAbsolute> listSubFile = directoryPathAbsolute1.ChildrenFilesPath;

 

   }

}


Posted 10-18-2007 2:55 PM by Patrick Smacchia
Filed under:

[Advertisement]

Comments

bwets wrote re: A free library to handle common and complex path operations
on 10-18-2007 4:42 PM

Awesome, makes you wonder how MS could have missed that! I had to write my own MakeRelative method, and it was such a pain... Thanks!

Scott Hanselman's Computer Zen wrote The Weekly Source Code 8
on 10-19-2007 3:05 AM
Jonathan de Halleux wrote re: A free library to handle common and complex path operations
on 10-19-2007 4:01 AM

Have you tried 'new FilePathRelative("/")' ? :)

Patrick Smacchia wrote re: A free library to handle common and complex path operations
on 10-19-2007 4:26 AM

"/" is not considered as a valid relative path, "." or "./" or ".\" is.

you can test like this:

string reason;

bool b = PathHelper.IsValidRelativePath("/", out reason);

and b will be false

bool b = PathHelper.IsValidAbsolutePath("/", out reason);

also returns false btw

Christopher Steen wrote Link Listing - October 18, 2007
on 10-19-2007 6:02 AM

Link Listing - October 18, 2007

Christopher Steen wrote Link Listing - October 18, 2007
on 10-19-2007 6:04 AM

How to build a Fluent Interface in C# [Via: blog@troyd.net (Troy DeMonbreun) ] SOA Security - Enterprise...

ASPInsiders wrote The Weekly Source Code 8
on 10-19-2007 6:11 AM

In my new ongoing quest to read source code to be a better developer , I now present the eighth an infinite

This Old Code wrote If Paths have you down
on 10-19-2007 9:29 AM

Add a Comment

(required)  
(optional)
(required)  
Remember Me?