Access files with long paths (over 260)
Asked Answered
A

3

9

I'm using Microsoft Scripting Runtime (FSO) to parse folders and produce a list of all of its contents, the folders are on a network and resultant paths end up longer than 260. The minimum code I have is as below:-

Private Sub ProcessFolder(ByVal StrFolder As String)
Dim Fl              As File
Dim Fldr            As Folder
Dim RootFldr        As Folder

Set RootFldr = FS.GetFolder(StrFolder)

    For Each Fl In RootFldr.Files
        Debug.Print Fl.Path
    Next

    For Each Fldr In RootFldr.SubFolders
        DoEvents
        ProcessFolder Fldr.Path
    Next

Set RootFldr = nothing    
End sub

At a certain level StrFolder length became 259, the Set RootFldr ... folder line worked but For Each Fl In RootFldr.Files gave the error of 76: Path not found, presumably because the content causes the path to breach the 260 limit.

There were files in the folder when looking in Windows Explorer. I am using Excel as the host for this code as I'm outputting the result to workbooks.

Just to be super clear on my question and its background, I need to use FSO (happy to be shown alternatives if they exist) to access files deeper than 260 characters deep in their network path. I need it as FSO as the tool I have is taking the folder paths and the file paths, name, size created, and modified.

Anglicanism answered 18/7, 2016 at 8:46 Comment(5)
Possible repeat: linkDangerous
Both similar and I feel bad for not providing more information from the start (and I thought I had done a good question!) I'll update with my further requirements, currently I'm using shortpath to get through it. It ruins the path (makes it non-human readable/usable) but I think I could write something to fix that.Anglicanism
Just an idea for workaround: Once you have reached probably 250 characters in file path, you could Map a new drive letter to it and recurs that, and another one when reached 500 characters originally. But you need to change the code to realize that to reconstruct the full path. This way in theory you can reach up to 25*250 characters.Enucleate
@Enucleate Its a probable idea and I think I tried that in a past project (way back). The issue was the limit is on the resultant path, i.e. after resolving the mapped drive to its path and prefixing it to the path you are trying to get to.Anglicanism
@Patrick The solution I was thinking of was similar. I was thinking of running PUSHD and POPD in a WshSell because command's DIR is very well optimized for searching directories (much faster than using FSO). However, once I saw Hans' answer, it was pointless. His is far superior.Gemot
A
4

This took a little creative coding but the use of ShortPath was the answer.

This tool was to create a list of every folder and file in a root folder, the files also showing their size, and created/modified dates. The issue was when the resultant path of a file or folder was over 260, then the error Error 76: Path Not Found was thrown and the code would not capture the content of that area.

Using Microsoft Scripting Runtime (FSO) ShortPath would get around this issue but the path went from human readable to coded:-

Full path \\ServerName00000\Root_Root_contentmanagement\DPT\STANDARDS_GUIDELINES\VENDOR_CERTIFICATION_FILES\PDFX_CERTIFICATION_ALL\2006_2007\DPT\CompantName0\Approved\Quark\India under Colonial Rule_structure sample\058231738X\Douglas M. Peers_01_058231738X\SUPPORT\ADDITIONAL INFORMATION\IUC-XTG & XML file

Short Path \\lo3uppesaapp001\pesa_cmcoe_contentmanagement\CTS\S4SJ05~5\V275SE~8\PDM5D9~G\2N52EQ~5\HPE\GS9C6L~U\Approved\Quark\IQPSJ5~F\0CWHH1~G\DOFNHA~8\SUPPORT\A6NO7S~K\IUC-XTG & XML file

(Note I've altered the full path to protect IP and company info but the size is the same)

You can see while I could pass short path to someone and they could put it into Windows Explorer to get there, they would know know where it went by simply looking, to get around this a used a global variable that kept the folder path as a full string and followed what the short path was doing. this string is then what I output to the user. The below code is cut down but shows how I achieved it.

The short answer is ShortPath in FSO will get past the issue but the path will not be pretty.

Dim FS              As New FileSystemObject
Dim LngRow          As Long
Dim StrFolderPath   As String
Dim WkBk            As Excel.Workbook
Dim WkSht           As Excel.Worksheet

Public Sub Run_Master()

Set WkBk = Application.Workbooks.Add

    WkBk.SaveAs ThisWorkbook.Path & "\Data.xlsx"

    Set WkSht = WkBk.Worksheets(1)

        WkSht.Range("A1") = "Path"
        WkSht.Range("B1") = "File Name"
        WkSht.Range("C1") = "Size (KB)"
        WkSht.Range("D1") = "Created"
        WkSht.Range("E1") = "Modified"

        LngRow = 2

        Run "\\ServerName00000\AREA_DEPT0_TASK000"

    Set WkSht = Nothing

    WkBk.Close 1
Set WkBk = Nothing

MsgBox "Done!"

End Sub

Private Sub Run(ByVal StrVolumeToCheck As String)
Dim Fldr            As Folder
Dim Fldr2           As Folder

Set Fldr = FS.GetFolder(StrVolumeToCheck)

    'This is the variable that follows the full path name
    StrFolderPath = Fldr.Path

    WkSht.Range("A" & LngRow) = StrFolderPath
    LngRow = LngRow +1

    For Each Fldr2 In Fldr.SubFolders
        If (Left(Fldr2.Name, 1) <> ".") And (UCase(Trim(Fldr2.Name)) <> "LOST+FOUND") Then
            ProcessFolder Fldr2.Path
        End If
    Next

Set Fldr = Nothing

End Sub

Private Sub ProcessFolder(ByVal StrFolder As String)
'This is the one that will will be called recursively to list all files and folders
Dim Fls             As Files
Dim Fl              As File
Dim Fldrs           As Folders
Dim Fldr            As Folder
Dim RootFldr        As Folder

Set RootFldr = FS.GetFolder(StrFolder)

    If (RootFldr.Name <> "lost+found") And (Left(RootFldr.Name, 1) <> ".") Then

        'Add to my full folder path
        StrFolderPath = StrFolderPath & "\" & RootFldr.Name

        WkSht.Range("A" & LngRow) = StrFolderPath
        WkSht.Range("D1") = RootFldr.DateCreated
        WkSht.Range("E1") = RootFldr.DateLastModified
        Lngrow = LngRow + 1

        'This uses the short path to get the files in FSO
        Set Fls = FS.GetFolder(RootFldr.ShortPath).Files

            For Each Fl In Fls
                'This output our string variable of the path (i.e. not the short path)
                WkSht.Range("A" & LngRow) = StrFolderPath
                WkSht.Range("B" & LngRow) = Fl.Name
                WkSht.Range("C" & LngRow) = Fl.Size /1024 '(bytes to kilobytes)
                WkSht.Range("D" & LngRow) = Fl.DateCreated
                WkSht.Range("E" & LngRow) = Fl.DateLastModified

                LngRow = LngRow + 1

            Next
        Set Fls = Nothing

        'This uses the short path to get the sub-folders in FSO
        Set Fldrs = FS.GetFolder(RootFldr.ShortPath).SubFolders
            For Each Fldr In Fldrs
                'Recurse this Proc
                ProcessFolder Fldr.Path
                DoEvents
            Next
        Set Fldrs = Nothing

        'Now we have processed this folder, trim the folder name off of the string
        StrFolderPath = Left(StrFolderPath, Len(StrFolderPath) - Len(RootFldr.Name)+1)

    End If
Set RootFldr = Nothing

End Sub

As mentioned this is a cut version of the code that is working for me to exemplify the the method used to get past this limit. Actually seems quite rudimentary once I'd done it.

Anglicanism answered 25/7, 2016 at 10:55 Comment(1)
wow, works nicely, thanks! Just one thing, it may possibly fail if fl.name starts with the "=" character (e.g. file named =.md). I added the line WkSht.Range("B" & LngRow).NumberFormat = "@" (cell "Text" format instead of "General") before WkSht.Range("B" & LngRow) = Fl.Name.Hillary
A
15

The technique to convert MAXFILE encumbered DOS path names to native OS path names is well established and documented. Summarizing:

  • Prefix a path that uses a drive letter with \\?\, like \\?\C:\foo\bar\baz.txt
  • Prefix a path that uses a file share with '\\?\UNC\, like \\?\UNC\server\share\baz.txt.

Works well with FileSystemObject too, at least when I tested your code on Windows 10. That might not necessarily be the case in older Windows versions or with the network redirector on your server. Tested by using the FAR file manager to create subdirectories with long names and verified with:

Dim path = "\\?\C:\temp\LongNameTest"
ProcessFolder path

Produced:

\\?\c:\temp\LongNameTest\VeryLongFolderName0123456789012345678901234567890123456789012345678901234567890123456789\VeryLongFolderName0123456789012345678901234567890123456789012345678901234567890123456789\VeryLongFolderName0123456789012345678901234567890123456789012345678901234567890123456789\VeryLongFolderName0123456789012345678901234567890123456789012345678901234567890123456789\VeryLongFolderName0123456789012345678901234567890123456789012345678901234567890123456789\Chrysanthemum.jpg

Which is 488 characters long. Things to keep in mind:

  • Native path names must be full paths, they cannot be relative paths. In other words, they must always start with a drive letter or share name and start from the root of the drive/share.
  • You get the native path name back, don't forget to strip the prefix off again if you display it.
  • Not tested but should fail, there is still a limitation on the the length of the filename itself (without the directory names), can't be longer than 259 chars. Shouldn't be a problem at all since the user can't create them either.
Aegeus answered 23/7, 2016 at 11:44 Comment(4)
How did you test this on FSO? I can't get it to work, I need to get the file size, modified and created date, I was using Set FSFldr = FS.GetFolder("\\?\lo3uppesaapp001\pesa_cmc....)Anglicanism
That is not a valid path, review the post again. Best guess is \\?\UNC\lo3uppesaapp001\pesa_cmc...Aegeus
Hi, I know its not a valid path, I didn't want to post what was a live folder path and clog up the message. I'm going by what I have read in the answerAnglicanism
To specify such a path using UNC, use the "\\?\UNC\" prefix. For example, "\\?\UNC\server\share", where "server" is the name of the computer and "share" is the name of the shared folder. So your example path would be \\?\UNC\lo3uppesaapp001\pesa_cmc....Gemot
A
4

This took a little creative coding but the use of ShortPath was the answer.

This tool was to create a list of every folder and file in a root folder, the files also showing their size, and created/modified dates. The issue was when the resultant path of a file or folder was over 260, then the error Error 76: Path Not Found was thrown and the code would not capture the content of that area.

Using Microsoft Scripting Runtime (FSO) ShortPath would get around this issue but the path went from human readable to coded:-

Full path \\ServerName00000\Root_Root_contentmanagement\DPT\STANDARDS_GUIDELINES\VENDOR_CERTIFICATION_FILES\PDFX_CERTIFICATION_ALL\2006_2007\DPT\CompantName0\Approved\Quark\India under Colonial Rule_structure sample\058231738X\Douglas M. Peers_01_058231738X\SUPPORT\ADDITIONAL INFORMATION\IUC-XTG & XML file

Short Path \\lo3uppesaapp001\pesa_cmcoe_contentmanagement\CTS\S4SJ05~5\V275SE~8\PDM5D9~G\2N52EQ~5\HPE\GS9C6L~U\Approved\Quark\IQPSJ5~F\0CWHH1~G\DOFNHA~8\SUPPORT\A6NO7S~K\IUC-XTG & XML file

(Note I've altered the full path to protect IP and company info but the size is the same)

You can see while I could pass short path to someone and they could put it into Windows Explorer to get there, they would know know where it went by simply looking, to get around this a used a global variable that kept the folder path as a full string and followed what the short path was doing. this string is then what I output to the user. The below code is cut down but shows how I achieved it.

The short answer is ShortPath in FSO will get past the issue but the path will not be pretty.

Dim FS              As New FileSystemObject
Dim LngRow          As Long
Dim StrFolderPath   As String
Dim WkBk            As Excel.Workbook
Dim WkSht           As Excel.Worksheet

Public Sub Run_Master()

Set WkBk = Application.Workbooks.Add

    WkBk.SaveAs ThisWorkbook.Path & "\Data.xlsx"

    Set WkSht = WkBk.Worksheets(1)

        WkSht.Range("A1") = "Path"
        WkSht.Range("B1") = "File Name"
        WkSht.Range("C1") = "Size (KB)"
        WkSht.Range("D1") = "Created"
        WkSht.Range("E1") = "Modified"

        LngRow = 2

        Run "\\ServerName00000\AREA_DEPT0_TASK000"

    Set WkSht = Nothing

    WkBk.Close 1
Set WkBk = Nothing

MsgBox "Done!"

End Sub

Private Sub Run(ByVal StrVolumeToCheck As String)
Dim Fldr            As Folder
Dim Fldr2           As Folder

Set Fldr = FS.GetFolder(StrVolumeToCheck)

    'This is the variable that follows the full path name
    StrFolderPath = Fldr.Path

    WkSht.Range("A" & LngRow) = StrFolderPath
    LngRow = LngRow +1

    For Each Fldr2 In Fldr.SubFolders
        If (Left(Fldr2.Name, 1) <> ".") And (UCase(Trim(Fldr2.Name)) <> "LOST+FOUND") Then
            ProcessFolder Fldr2.Path
        End If
    Next

Set Fldr = Nothing

End Sub

Private Sub ProcessFolder(ByVal StrFolder As String)
'This is the one that will will be called recursively to list all files and folders
Dim Fls             As Files
Dim Fl              As File
Dim Fldrs           As Folders
Dim Fldr            As Folder
Dim RootFldr        As Folder

Set RootFldr = FS.GetFolder(StrFolder)

    If (RootFldr.Name <> "lost+found") And (Left(RootFldr.Name, 1) <> ".") Then

        'Add to my full folder path
        StrFolderPath = StrFolderPath & "\" & RootFldr.Name

        WkSht.Range("A" & LngRow) = StrFolderPath
        WkSht.Range("D1") = RootFldr.DateCreated
        WkSht.Range("E1") = RootFldr.DateLastModified
        Lngrow = LngRow + 1

        'This uses the short path to get the files in FSO
        Set Fls = FS.GetFolder(RootFldr.ShortPath).Files

            For Each Fl In Fls
                'This output our string variable of the path (i.e. not the short path)
                WkSht.Range("A" & LngRow) = StrFolderPath
                WkSht.Range("B" & LngRow) = Fl.Name
                WkSht.Range("C" & LngRow) = Fl.Size /1024 '(bytes to kilobytes)
                WkSht.Range("D" & LngRow) = Fl.DateCreated
                WkSht.Range("E" & LngRow) = Fl.DateLastModified

                LngRow = LngRow + 1

            Next
        Set Fls = Nothing

        'This uses the short path to get the sub-folders in FSO
        Set Fldrs = FS.GetFolder(RootFldr.ShortPath).SubFolders
            For Each Fldr In Fldrs
                'Recurse this Proc
                ProcessFolder Fldr.Path
                DoEvents
            Next
        Set Fldrs = Nothing

        'Now we have processed this folder, trim the folder name off of the string
        StrFolderPath = Left(StrFolderPath, Len(StrFolderPath) - Len(RootFldr.Name)+1)

    End If
Set RootFldr = Nothing

End Sub

As mentioned this is a cut version of the code that is working for me to exemplify the the method used to get past this limit. Actually seems quite rudimentary once I'd done it.

Anglicanism answered 25/7, 2016 at 10:55 Comment(1)
wow, works nicely, thanks! Just one thing, it may possibly fail if fl.name starts with the "=" character (e.g. file named =.md). I added the line WkSht.Range("B" & LngRow).NumberFormat = "@" (cell "Text" format instead of "General") before WkSht.Range("B" & LngRow) = Fl.Name.Hillary
C
3

I got around this once using the subst command of the command shell. It allows you to assign a drive letter to a local path (kind of like a network share).

Crabbe answered 26/7, 2016 at 18:45 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.