How do I find files with a path length greater than 260 characters in Windows?

WindowsWindows XpXcopyMax Path

Windows Problem Overview


I'm using a xcopy in an XP windows script to recursively copy a directory. I keep getting an 'Insufficient Memory' error, which I understand is because a file I'm trying to copy has too long a path. I can easily reduce the path length, but unfortunately I can't work out which files are violating the path length restriction. The files that are copied are printed to the standard output (which I'm redirecting to a log file), but the error message is printed to the terminal, so I can't even work out approximately which directory the error is being given for.

Windows Solutions


Solution 1 - Windows

do a dir /s /b > out.txt and then add a guide at position 260

In powershell cmd /c dir /s /b |? {$_.length -gt 260}

Solution 2 - Windows

I created the Path Length Checker tool for this purpose, which is a nice, free GUI app that you can use to see the path lengths of all files and directories in a given directory.

I've also written and blogged about a simple PowerShell script for getting file and directory lengths. It will output the length and path to a file, and optionally write it to the console as well. It doesn't limit to displaying files that are only over a certain length (an easy modification to make), but displays them descending by length, so it's still super easy to see which paths are over your threshold. Here it is:

$pathToScan = "C:\Some Folder"  # The path to scan and the the lengths for (sub-directories will be scanned as well).
$outputFilePath = "C:\temp\PathLengths.txt" # This must be a file in a directory that exists and does not require admin rights to write to.

$writeToConsoleAsWell = $true   # Writing to the console will be much slower.
 
# Open a new file stream (nice and fast) and write all the paths and their lengths to it.
$outputFileDirectory = Split-Path $outputFilePath -Parent
if (!(Test-Path $outputFileDirectory)) { New-Item $outputFileDirectory -ItemType Directory }
$stream = New-Object System.IO.StreamWriter($outputFilePath, $false)
Get-ChildItem -Path $pathToScan -Recurse -Force | Select-Object -Property FullName, @{Name="FullNameLength";Expression={($_.FullName.Length)}} | Sort-Object -Property FullNameLength -Descending | ForEach-Object {
    $filePath = $_.FullName
    $length = $_.FullNameLength
    $string = "$length : $filePath"
     
    # Write to the Console.
    if ($writeToConsoleAsWell) { Write-Host $string }
  
    #Write to the file.
    $stream.WriteLine($string)
}
$stream.Close()

Solution 3 - Windows

As a refinement of simplest solution, and if you can’t or don’t want to install Powershell, just run:

dir /s /b | sort /r /+261 > out.txt

or (faster):

dir /s /b | sort /r /+261 /o out.txt

And lines longer than 260 will get to the top of listing. Note that you must add 1 to SORT column parameter (/+n).

Solution 4 - Windows

I've made an alternative to the other good answers on here that uses PowerShell, but mine also saves the list to a file. Will share it here in case anyone else needs wants something like that.

Warning: Code overwrites "longfilepath.txt" in the current working directory. I know it's unlikely you'd have one already, but just in case!

Purposely wanted it in a single line:

Out-File longfilepath.txt ; cmd /c "dir /b /s /a" | ForEach-Object { if ($_.length -gt 250) {$_ | Out-File -append longfilepath.txt}}

Detailed instructions:

  1. Run PowerShell
  2. Traverse to the directory you want to check for filepath lengths (C: works)
  3. Copy and paste the code [Right click to paste in PowerShell, or Alt + Space > E > P]
  4. Wait until it's done and then view the file: cat longfilepath.txt | sort

Explanation:

Out-File longfilepath.txt ; – Create (or overwrite) a blank file titled 'longfilepath.txt'. Semi-colon to separate commands.

cmd /c "dir /b /s /a" | – Run dir command on PowerShell, /a to show all files including hidden files. | to pipe.

ForEach-Object { if ($_.length -gt 250) {$_ | Out-File -append longfilepath.txt}} – For each line (denoted as $_), if the length is greater than 250, append that line to the file.

Solution 5 - Windows

From http://www.powershellmagazine.com/2012/07/24/jaap-brassers-favorite-powershell-tips-and-tricks/:

Get-ChildItem –Force –Recurse –ErrorAction SilentlyContinue –ErrorVariable AccessDenied

the first part just iterates through this and sub-folders; using -ErrorVariable AccessDenied means push the offending items into the powershell variable AccessDenied.

You can then scan through the variable like so

$AccessDenied |
Where-Object { $_.Exception -match "must be less than 260 characters" } |
ForEach-Object { $_.TargetObject }

If you don't care about these files (may be applicable in some cases), simply drop the -ErrorVariable AccessDenied part.

Solution 6 - Windows

you can redirect stderr.

more explanation here, but having a command like:

MyCommand >log.txt 2>errors.txt

should grab the data you are looking for.

Also, as a trick, Windows bypasses that limitation if the path is prefixed with \\?\ (msdn)

Another trick if you have a root or destination that starts with a long path, perhaps SUBST will help:

SUBST Q: "C:\Documents and Settings\MyLoginName\My Documents\MyStuffToBeCopied"
Xcopy Q:\ "d:\Where it needs to go" /s /e
SUBST Q: /D

Solution 7 - Windows

TLPD ("too long path directory") is the program that saved me. Very easy to use:

https://sourceforge.net/projects/tlpd/

Solution 8 - Windows

For paths greater than 260:
you can use:

Get-ChildItem | Where-Object {$_.FullName.Length -gt 260}

Example on 14 chars:
To view the paths lengths:

Get-ChildItem | Select-Object -Property FullName, @{Name="FullNameLength";Expression={($_.FullName.Length)}

Get paths greater than 14:

Get-ChildItem | Where-Object {$_.FullName.Length -gt 14}  

Screenshot:
enter image description here

For filenames greater than 10:

Get-ChildItem | Where-Object {$_.PSChildName.Length -gt 10}

Screenshot:
enter image description here

Solution 9 - Windows

Crazily, this question is still relevant. None of the answers gave me quite what I wanted although E235 gave me the base. I also print out the length of the name to make it easier to see how many characters one has to trim.

Get-ChildItem -Recurse | Where-Object {$_.FullName.Length -gt 260} | %{"{0} : {1}" -f $_.fullname.Length,$_.fullname }

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionWestHamsterView Question on Stackoverflow
Solution 1 - WindowsrerunView Answer on Stackoverflow
Solution 2 - WindowsdeadlydogView Answer on Stackoverflow
Solution 3 - WindowsChungalinView Answer on Stackoverflow
Solution 4 - WindowsRani KheirView Answer on Stackoverflow
Solution 5 - WindowsJonnoView Answer on Stackoverflow
Solution 6 - WindowsSeanCView Answer on Stackoverflow
Solution 7 - WindowspollarisView Answer on Stackoverflow
Solution 8 - WindowsE235View Answer on Stackoverflow
Solution 9 - WindowshoustenView Answer on Stackoverflow