Resolved Normalize path with length more than 260 chars

fedry

Member
Joined
Mar 25, 2008
Messages
8
Programming Experience
Beginner
Hello all,

My issue is to combine two paths which one or both of them may contain double dots. I used Path.Combine(string, string) and the returned string is still a long path as a result of concatenating these two paths. Single or double dots are not eliminated.

So, I tried to use Path.GetFullPath(string) method with the concatenated path as the argument. PathTooLongException is thrown because this path has more than 260 characters. However, if this path is normalized, it won't exceed the maximum characters for a file path.

Anybody knows any API available in .NET to solve this issue?

VB.NET:
Dim s As String = Path.Combine("D:\test1\test2\test3\test4\..\..\test3\test4\..\..\test3\test4\..\..\test3\test4\..\..\test3\test4\..\..\test3\test4\..\..\test3\test4\..\..\test3\test4\..\..\test3\test4\..\..\test3\test4\..\..\test3\test4\..\..\test3\test4\..\..\test3\test4\..\..\test3\test4\..\..\test3\test4\..\..\test3\test4\..\..\test3\test4\..\..\test3\test4\..\..\test3\test4\..\..\test3\test4\..\..\test3\test4\..\..\test3\test4\..\..\test3\test4\..\..\test3\test4\..\..\test3\test4\..\..\test3\test4\..\..\test3\test4\..\..\test3\test4\..\..\test3\test4\..\..\test3\test4\..\..\test3\test4\..\..\test3\test4\..\..\test3\test4\..\..\test3\test4\..\..\test3\test4\..\..\test3\test4\..\..\test3\test4\..\..\test3\test4\..\..\test3\test4\..\..\test3\test4\..\..\test3\test4\..\..\test3\test4\..\..\test3\test4\..\..\test3\test4\..\..\test3\test4\..\..\test3\test4\..\..\test3\test4\..\..\test3\test4\..\..\test3\test4\..\..\test3\test4\..\..\test3\test4\..\..\test3\test4\..\..\test3\test4\..\..\test3\test4\..\..\test3\test4\..\..\test3\test4\..\..\test3\test4\..\..\test3\test4\..\..\test3\test4\..\..\test3\test4\..\..\test3\test4\..\..\test3\test4\..\..\test3\test4\..\..\test3\test4\..\..\test3\test4\..\..\test3\test4\..\..\test3\test4\..\..\test3\test4\..\..\test3\test4\..\..\test3\test4\..\..\test3\test4\..\..\test3\test4\..\..\test3\test4\..\..\test3\test4\..\..\test3\test4\..\..\test3\test4\..\..\test3\test4\..\..\test3\test4\..\..\test3\test4\..\..\test3\test4\..\..\test3\test4\..\..\test3\test4\..\..\test3\test4\..\..\test3\test4\..\..\test3\test4\..\..\test3\test4\..\..\test3\test4\..\..\test3\test4\..\..\test3\test4\..\..\test3\test4\..\..\test3\test4\..\..\test3\test4\..\..\test3\test4\..\..\test3\test4\..\..\test3\test4\..\..\test3\test4\..\..\test3\test4\..\..\test3\test4\..\..\test3\test4\..\..\test3\test4\..\..\test3\test4\..\..\test3\test4\..\..\test3\test4\..\..\test3\test4\..\..\test3\test4\..\..\test3\test4\..\..\test3\test4\..\..\test3\test4\..\..\test3\test4\..\..\test3\test4\..\..\test3\test4\..\..\test3\test4\..\..\test3\test4\", "..\test.txt")
Dim f As FileInfo = New FileInfo(Path.GetFullPath(s))

--
Thank you,
Fedry
 
Last edited:
when two of the parts combined doesn't exceed limit:
VB.NET:
Dim s = IO.Path.Combine("D:\test1\test2\test3\test4\", "..\..\test3\test4\")
s = IO.Path.GetFullPath(s)
 
Yup, that's exactly how I did it.
However, an exception will be thrown if variable "s" has exceeded 260 characters as Path.Combine doesn't normalize the double dots of path.:(
 
If it also not difficult to write a Normalize function. Split the string by DirectorySeparatorChar and iterate the parts backwards. If part is ".." remove it and increase a counter, else if count>0 remove the part and decrease the counter (have an exit clause here when iterator=0 and also part contains VolumeSeparatorChar, reset count if rooted). Within same loop also empty parts (as displayed \\ in path) can be removed. After loop if count>0 that mean it was a relative path, insert count number of ".." parts to beginning of collection. Join the parts collection with DirectorySeparatorChar to the new path string when done.
 
thanks for the idea :). I implemented it a little bit different.
I shared the code below in case somebody want to have a look.

VB.NET:
    Public Shared Function CombinePaths(ByVal path1 As String, ByVal path2 As String) As String
        ' Combine two paths, any exception will be thrown directly
        Dim newPath As String = Path.Combine(path1, path2)

        Try
            ' Try to get the absolute path
            newPath = Path.GetFullPath(newPath)

        Catch ptlex As PathTooLongException
            ' We may have a problem with path with more than 260 chars
            ' Split all folders and file name into array
            Dim items As List(Of String) = New List(Of String)(newPath.Split(New Char() {Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar}))
            Dim newItems As New List(Of String)

            ' Get the root name if exist
            Dim root As String = items(0)
            If root.Contains(":") Then
                items.RemoveAt(0)
            Else
                root = ""
            End If

            ' Remove all the dots while copying the folders and file name array into new array

            For Each item As String In items
                If item.Equals(".") Then
                    ' Ignore single dot
                ElseIf item.Equals("..") Then
                    ' Remove the previous folder
                    If newItems.Count > 0 Then
                        newItems.RemoveAt(newItems.Count - 1)
                    End If
                Else
                    ' Add this folder or file name
                    newItems.Add(item)
                End If
            Next

            ' Insert the root name in the beginning of new array
            newItems.Insert(0, root)

            ' Execute again the GetFullPath on the simplified path
            newPath = Path.GetFullPath(String.Join(Path.DirectorySeparatorChar, newItems.ToArray))
        Catch
            ' Other exceptions, just re-throw them
            Throw
        End Try

        Return newPath
    End Function
 
A short version:
VB.NET:
Dim shortPath = longPath.Replace("\.\", "\")

Dim r as New Regex("\\[^\\]*?\\[.]{2}\\")
Dim len as Integer = 0
Do
  len = shortPath.Length
  shortPath = r.Replace(shortPath, "\")
While shortPath.Length < len

An optimised version, use only when your folder names do not start with double dot:
VB.NET:
Dim shortPath = longPath.Replace("\.\", "\")

Dim r as New Regex("\\[^\\]*?\\[.]{2}")
Dim len as Integer = 0
Do
  len = shortPath.Length
  shortPath = r.Replace(shortPath, "")
While shortPath.Length < len


I do believe that tokenizing the string and pathing it out is better. For your container I'd have used a LinkedList or a Stack though. Tokenize and push onto the stack everything that is not "..", pop when you encounter ".."
Consider replacing \.\ with nothing before you start
 

Latest posts

Back
Top