Como encontro arquivos com um comprimento de caminho superior a 260 caracteres no Windows?

87

Estou usando um xcopy em um script do Windows XP para copiar recursivamente um diretório. Sempre recebo um erro de 'Memória insuficiente', que entendi ser porque um arquivo que estou tentando copiar tem um caminho muito longo. Posso reduzir facilmente o comprimento do caminho, mas infelizmente não consigo descobrir quais arquivos estão violando a restrição de comprimento do caminho. Os arquivos copiados são impressos na saída padrão (que estou redirecionando para um arquivo de log), mas a mensagem de erro é impressa no terminal, então não consigo nem descobrir aproximadamente para qual diretório o erro está sendo fornecido .

WestHamster
fonte

Respostas:

114

faça um dir /s /b > out.txte, em seguida, adicione um guia na posição 260

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

repetir
fonte
1
dir / s / b> out.txt faz o trabalho perfeitamente. Obrigado. "'Get-ChildItem' não é reconhecido como um comando interno ou externo, programa operável ou arquivo em lote." Acho que não tenho PowerShell.
WestHamster,
1
@WestHamster, você terá que executar esse comando no console do PowerShell.
Rami A.
6
Ele apresenta um erro como: Get-ChildItem : The specified path, file name, or both are too long. The fully qualified file name must be less than 260 characters, and the directory name must be less than 248 characters.Junto com ele, apenas um caminho reduzido é impresso. por exemplo: D:\Dropbox\ProY...sh._setbinddata. Esses são exatamente os caminhos que quero encontrar, mas não consigo ver o caminho completo! Alguma maneira de contornar isso?
MiniGod
Eu sou o único que não consegue fazer isso funcionar? Usando Win7 64 bits Home Premium, Powershell 2.0 - quando eu crio um arquivo de teste com um nome longo (240 caracteres) e, em seguida, renomeio o diretório no qual ele se encontra para também ter um nome longo, Get-ChildItems -r *para de ver o arquivo ... só dir /s /bfunciona para mim.
Jonas Heidelberg
Veja minha resposta para uma maneira de fazer isso no PowerShell, permitindo que você encontre os nomes de arquivo ofensivos (aqueles acima de 260 caracteres) ou, alternativamente, ignore-os.
Jonno,
31

Eu criei a ferramenta Path Length Checker para esse propósito, que é um bom aplicativo GUI gratuito que você pode usar para ver os comprimentos de caminho de todos os arquivos e diretórios em um determinado diretório.

Também escrevi e bloguei sobre um script simples do PowerShell para obter tamanhos de arquivo e diretório. Ele irá mostrar o comprimento e o caminho para um arquivo e, opcionalmente, gravá-lo no console também. Ele não se limita a exibir arquivos que têm apenas um determinado comprimento (uma modificação fácil de fazer), mas os exibe em ordem decrescente de comprimento, então ainda é muito fácil ver quais caminhos estão acima do seu limite. Aqui está:

$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()
cachorro mortal
fonte
2
Script interessante, mas ainda estou recebendo este erro: Get-ChildItem : The specified path, file name, or both are too long. The fully qualified file name must be less than 260 characters, and the directory name must be less than 248 characters.
zkurtz
Excelente ferramenta !! Eu tinha um grande encontro, queria criar um backup em um WD MyCloud HDD. Por esta ferramenta veio a saber o comprimento máximo para criar uma estrutura de pastas no HDD. Obrigado.
NJMR
27

Como um refinamento da solução mais simples, e se você não puder ou não quiser instalar o Powershell, basta executar:

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

ou (mais rápido):

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

E as linhas com mais de 260 chegarão ao topo da lista. Observe que você deve adicionar 1 ao parâmetro da coluna SORT (/ + n).

Chungalin
fonte
Obrigado pelo refinamento. No meu caso, não consegui instalar o Powershell (caixa do Windows 2003). VOTADO
etapa
Você pode explicar por que você tem que adicionar 1 em mais detalhes?
Xonatron
Existe uma maneira de classificar o arquivo de saída pelo comprimento da linha?
Xonatron
@Xonatron, "E linhas com mais de 260"
penhasco de
Votado. Eu acho que isso também deve mencionar SUBST para encurtar um caminho em um ftw de unidade.
precipício de
6

Fiz uma alternativa para as outras boas respostas aqui que usam PowerShell, mas a minha também salva a lista em um arquivo. Vou compartilhar aqui, caso alguém precise e queira algo assim.

Aviso: o código sobrescreve "longfilepath.txt" no diretório de trabalho atual. Eu sei que é improvável que você já tenha um, mas apenas no caso!

Desejado propositalmente em uma única linha:

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

Instruções detalhadas:

  1. Execute PowerShell
  2. Vá até o diretório em que deseja verificar os comprimentos do caminho de arquivo (C: funciona)
  3. Copie e cole o código [clique com o botão direito para colar no PowerShell ou Alt + Espaço> E> P]
  4. Espere até terminar e veja o arquivo: cat longfilepath.txt | sort

Explicação:

Out-File longfilepath.txt ;- Crie (ou substitua) um arquivo em branco intitulado 'longfilepath.txt'. Ponto-e-vírgula para separar comandos.

cmd /c "dir /b /s /a" |- Execute o comando dir no PowerShell, /apara mostrar todos os arquivos, incluindo arquivos ocultos. |para canalizar.

ForEach-Object { if ($_.length -gt 250) {$_ | Out-File -append longfilepath.txt}} - Para cada linha (denotada como $ _), se o comprimento for maior que 250, anexe essa linha ao arquivo.

Rani Kheir
fonte
2

você pode redirecionar stderr.

mais explicação aqui , mas com um comando como:

MyCommand >log.txt 2>errors.txt

deve obter os dados que você está procurando.

Além disso, como um truque, o Windows contorna essa limitação se o caminho for prefixado com \\?\( msdn )

Outro truque, se você tiver uma raiz ou destino que começa com um longo caminho, talvez SUBSTajude:

SUBST Q: "C:\Documents and Settings\MyLoginName\My Documents\MyStuffToBeCopied"
Xcopy Q:\ "d:\Where it needs to go" /s /e
SUBST Q: /D
SeanC
fonte
Redirecionar a saída std e os erros deve me dar uma indicação boa o suficiente de onde está o arquivo grande, obrigado. comando> arquivo 2> & 1
WestHamster
isso vai funcionar, mas meu comando deve separar os erros em um arquivo separado
SeanC
\\? \ também parece bom. Não consigo fazer o seguinte funcionar: xcopy / s \\? \ Q: \ nuthatch \\? \ Q: \ finch
WestHamster
hmm ... parece \\?\ que não funciona para a linha de comando. Adicionada outra ideia usandoSUBST
SeanC
Infelizmente subst não será muito útil porque o comando é do tipo: xcopy / sq: \ nuthatch q: \ finch <br/> e o caminho longo está embutido em algum lugar desconhecido sob nuthatch
WestHamster
2

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

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

a primeira parte apenas itera por meio desta e das subpastas; usar -ErrorVariable AccessDeniedsignifica empurrar os itens ofensivos para a variável powershell AccessDenied.

Você pode então percorrer a variável assim

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

Se você não se importa com esses arquivos (podem ser aplicáveis ​​em alguns casos), simplesmente descarte a -ErrorVariable AccessDeniedparte.

Jonno
fonte
O problema é $_.TargetObjectque não contém o caminho completo para os arquivos violados MAX_PATH, apenas os nomes dos diretórios e o nome do diretório pai dos arquivos ofensivos. Estou trabalhando para encontrar uma solução que não seja Robocopy, Subst ou Xcopy e postarei quando encontrar uma solução que funcione.
user66001
-2

Para caminhos maiores que 260:
você pode usar:

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

Exemplo em 14 caracteres:
Para visualizar os comprimentos dos caminhos:

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

Obtenha caminhos maiores que 14:

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

Captura de tela:
insira a descrição da imagem aqui

Para nomes de arquivos maiores que 10:

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

Captura de tela:
insira a descrição da imagem aqui

E235
fonte
4
Você obviamente não tem ideia do problema. Nada do que você sugeriu funciona. Por favor, leia
n0rd