Darrell Norton's Blog [MVP]

Sponsors

The Lounge

News

  • Darrell Norton pic

    MVP logo

    View Darrell Norton's profile on LinkedIn

    Currently Reading:

    weewar.com

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 Path.Combine method that takes any number of arguments

Python has a function similar to the .NET Framework’s Path.Combine method, except that Python can take any number of string parameters. I decided to port this to .NET. Here’s the code for a Utils.Path.Combine method that takes a string array of paths and returns the concatenated path:

     1: using System;
     2: using System.Text;
     3: using ioPath = System.IO.Path;
     4:  
     5: namespace Utils
     6: {
     7:     public sealed class Path
     8:     {
     9:         private Path() { }
    10:  
    11:         public static string Combine(params string[] paths) {
    12:             if (paths.Length == 2) return ioPath.Combine( paths[0], paths[1] );
    13:  
    14:             StringBuilder combined = new StringBuilder(50);
    15:             foreach(string path in paths) {
    16:                 if (path == null) throw new ArgumentNullException("path array item");
    17:                 Path.CheckInvalidPathChars(path);
    18:                 if ( path.Length > 0 ) {
    19:                     if (ioPath.IsPathRooted(path)) {
    20:                         combined = new StringBuilder(50).Append(path);
    21:                     }
    22:                     else {
    23:                         char ch1;
    24:                         if (combined.Length > 0) {
    25:                             ch1 = combined[combined.Length - 1];
    26:                         }
    27:                         else {
    28:                             ch1 = path[path.Length - 1];
    29:                         }
    30:                         if (((ch1 != ioPath.DirectorySeparatorChar) && 
    31:                                 (ch1 != ioPath.AltDirectorySeparatorChar)) && 
    32:                                 (ch1 != ioPath.VolumeSeparatorChar)) {
    33:                             combined.Append(ioPath.DirectorySeparatorChar);
    34:                             combined.Append(path);
    35:                         }
    36:                         else {
    37:                             combined.Append(path);
    38:                         }
    39:  
    40:                     }
    41:                 }
    42:             }
    43:             return combined.ToString();
    44:         }
    45:  
    46:         internal static void CheckInvalidPathChars(string path) {
    47:             if (-1 != path.IndexOfAny(System.IO.Path.InvalidPathChars)) {
    48:                 throw new ArgumentException("InvalidPathChars");
    49:             }
    50:         }
    51:     }
    52: }

You call it like this:

1: result = Path.Combine( @"C:\ProgramFiles", "someDir", @"anotherDir\", "someFile.txt" );

I tried to call the Path class's public members as much as possible to improve upgradability to the next version of the .NET Framework. The CheckInvalidPathChars internal method is the same as the System.IO.Path class's method of the same name. I used Reflector to check it out.

From my performance testing, the built-in Path.Combine performs about 60 nanoseconds faster on two arguments. For three arguments or more, it outperforms the built-in function in an increasing manner. Maybe it's not all that useful, but it was fun to do.

I did use Test-Driven Development, I just didn't show the code. The majority of the effort was in performance tuning, but the test harness kept the code running as intended.

Update: Changed lines 33-34 per James Curran's suggestion. I missed the boxing that line would cause. Now the code clearly outperforms the built-in Combine method for any number of paths greater than two.


Posted 12-28-2004 10:57 AM by Darrell Norton

[Advertisement]

Comments

James Curran wrote re: A Path.Combine method that takes any number of arguments
on 12-28-2004 7:44 AM
Tsk, Tsk, Tsk...
>> combined.Append(ioPath.DirectorySeparatorChar + path);

What's the point of using a StringBUilder, if you're going to concatenate two (immutable) strings right in the middle of it?

combined.Append(ioPath.DirectorySeparatorChar);
combined.Append(path);
Darrell wrote re: A Path.Combine method that takes any number of arguments
on 12-28-2004 8:48 AM
James - ok, you got me! I let that one boxing call in. I fixed the code. It now performs better than Path.Combine for any number of paths > 2 (before it was only marginally faster at 3, but now it's a lot faster).

Thanks!