Comment trouver des fichiers dont la longueur de chemin est supérieure à 260 caractères dans Windows?

87

J'utilise un xcopy dans un script Windows XP pour copier récursivement un répertoire. Je continue à recevoir une erreur «Mémoire insuffisante», ce que je comprends, car un fichier que j'essaie de copier a un chemin trop long. Je peux facilement réduire la longueur du chemin, mais malheureusement, je ne peux pas déterminer quels fichiers enfreignent la restriction de longueur de chemin. Les fichiers copiés sont imprimés sur la sortie standard (que je redirige vers un fichier journal), mais le message d'erreur est imprimé sur le terminal, donc je ne peux même pas déterminer approximativement le répertoire pour lequel l'erreur est donnée .

WestHamster
la source

Réponses:

114

faire a dir /s /b > out.txtpuis ajouter un guide à la position 260

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

rediffusion
la source
1
dir / s / b> out.txt fait le travail à merveille. Merci. "'Get-ChildItem' n'est pas reconnu comme une commande interne ou externe, un programme utilisable ou un fichier de commandes." Je suppose que je n'ai pas de PowerShell.
WestHamster
1
@WestHamster, vous devrez exécuter cette commande dans la console PowerShell.
Rami A.
6
Il génère une erreur du type: 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.Parallèlement, seul un chemin raccourci est imprimé. par exemple: D:\Dropbox\ProY...sh._setbinddata. Ce sont exactement les chemins que je veux trouver, mais je ne peux pas voir tout le chemin! Un moyen de contourner cela?
MiniGod
Suis-je le seul à ne pas pouvoir faire fonctionner ça? En utilisant Win7 64 bits Home Premium, Powershell 2.0 - lorsque je crée un fichier de test avec un nom long (240 caractères) et que je renomme le répertoire dans lequel il se trouve pour avoir également un nom long, Get-ChildItems -r *cesse de voir le fichier ... ne dir /s /bfonctionne que pour moi.
Jonas Heidelberg
Voir ma réponse pour un moyen d'y parvenir dans PowerShell, vous permettant soit de trouver les noms de fichiers incriminés (ceux au-dessus de 260 caractères), soit de les ignorer.
Jonno
31

J'ai créé l'outil de vérification de la longueur du chemin à cette fin, qui est une belle application graphique gratuite que vous pouvez utiliser pour voir les longueurs de chemin de tous les fichiers et répertoires dans un répertoire donné.

J'ai également écrit et blogué sur un simple script PowerShell pour obtenir la longueur des fichiers et des répertoires. Il affichera la longueur et le chemin vers un fichier, et éventuellement l'écrira également sur la console. Il ne se limite pas à afficher les fichiers qui ne dépassent qu'une certaine longueur (une modification facile à faire), mais les affiche en ordre décroissant de longueur, il est donc toujours très facile de voir quels chemins dépassent votre seuil. C'est ici:

$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()
chien mortel
la source
2
Script intéressant, mais 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.
j'obtiens
Excellent outil !! J'avais une date énorme, je voulais créer une sauvegarde sur un disque dur WD MyCloud. Par cet outil est venu à connaître la longueur maximale pour créer une structure de dossiers sur le disque dur. Merci.
NJMR
27

Pour affiner la solution la plus simple, et si vous ne pouvez pas ou ne voulez pas installer Powershell, exécutez simplement:

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

ou (plus rapide):

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

Et les lignes de plus de 260 arriveront en tête de liste. Notez que vous devez ajouter 1 au paramètre de colonne SORT (/ + n).

Chongique
la source
Merci pour le raffinement. C'était mon cas que je ne pouvais pas installer Powershell (boîte Windows 2003). VOTE UP
avant le
Pouvez-vous expliquer pourquoi vous devez ajouter 1 plus en détail?
Xonatron
Existe-t-il un moyen de trier le fichier de sortie par longueur de ligne?
Xonatron
@Xonatron, "Et les lignes de plus de 260"
cliffclof
Up voté. Je pense que cela devrait également mentionner SUBST pour raccourcir un chemin dans un lecteur ftw.
cliffclof
6

J'ai fait une alternative aux autres bonnes réponses ici qui utilise PowerShell, mais la mienne enregistre également la liste dans un fichier. Je le partagerai ici au cas où quelqu'un d'autre aurait besoin de quelque chose comme ça.

Attention: le code écrase "longfilepath.txt" dans le répertoire de travail actuel. Je sais qu'il est peu probable que vous en ayez déjà un, mais juste au cas où!

Le voulait exprès en une seule ligne:

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

Des instructions détaillées:

  1. Exécutez PowerShell
  2. Accédez au répertoire dans lequel vous souhaitez vérifier les longueurs de chemin de fichier (C: fonctionne)
  3. Copiez et collez le code [clic droit pour coller dans PowerShell ou Alt + Espace> E> P]
  4. Attendez que ce soit terminé, puis affichez le fichier: cat longfilepath.txt | sort

Explication:

Out-File longfilepath.txt ;- Créez (ou écrasez) un fichier vierge intitulé 'longfilepath.txt'. Point-virgule pour séparer les commandes.

cmd /c "dir /b /s /a" |- Exécutez la commande dir sur PowerShell, /apour afficher tous les fichiers, y compris les fichiers cachés. |à la canalisation.

ForEach-Object { if ($_.length -gt 250) {$_ | Out-File -append longfilepath.txt}} - Pour chaque ligne (notée $ _), si la longueur est supérieure à 250, ajoutez cette ligne au fichier.

Rani Kheir
la source
2

vous pouvez rediriger stderr.

plus d'explications ici , mais ayant une commande comme:

MyCommand >log.txt 2>errors.txt

devrait saisir les données que vous recherchez.

De plus, comme astuce, Windows contourne cette limitation si le chemin est préfixé par \\?\( msdn )

Une autre astuce si vous avez une racine ou une destination qui commence par un long chemin, vous SUBSTaidera peut - être :

SUBST Q: "C:\Documents and Settings\MyLoginName\My Documents\MyStuffToBeCopied"
Xcopy Q:\ "d:\Where it needs to go" /s /e
SUBST Q: /D
SeanC
la source
La redirection de la sortie std et les erreurs devraient me donner une indication assez bonne de l'endroit où se trouve le gros fichier. commande> fichier 2> & 1
WestHamster
cela fonctionnera, mais ma commande devrait séparer les erreurs dans un fichier séparé
SeanC
\\? \ semble bon aussi. Je ne parviens pas à faire fonctionner les éléments suivants: xcopy / s \\? \ Q: \ nuthatch \\? \ Q: \ finch
WestHamster
hmm ... semble \\?\ ne pas fonctionner pour la ligne de commande. Ajout d'une autre idée utilisantSUBST
SeanC
Malheureusement, subst ne sera pas trop utile car la commande est du type: xcopy / sq: \ nuthatch q: \ finch <br/> et le long chemin est intégré quelque part inconnu sous
nuthatch
2

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

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

la première partie parcourt simplement ce dossier et ses sous-dossiers; en utilisant -ErrorVariable AccessDeniedsignifie pousser les éléments incriminés dans la variable powershell AccessDenied.

Vous pouvez ensuite parcourir la variable comme ceci

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

Si vous ne vous souciez pas de ces fichiers (peut être applicable dans certains cas), déposez simplement la -ErrorVariable AccessDeniedpièce.

Jonno
la source
Le problème est $_.TargetObjectque ne contient pas le chemin complet des fichiers qui violent MAX_PATH, uniquement les noms de répertoire et le nom de répertoire parent des fichiers incriminés. Je travaille sur la recherche d'une solution non-Robocopy ou Subst ou Xcopy, et publierai quand je trouverai une solution fonctionnelle.
user66001
-2

Pour les chemins supérieurs à 260:
vous pouvez utiliser:

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

Exemple sur 14 caractères:
Pour afficher les longueurs des chemins:

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

Obtenez des chemins supérieurs à 14:

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

Capture d'écran:
entrez la description de l'image ici

Pour les noms de fichiers supérieurs à 10:

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

Capture d'écran:
entrez la description de l'image ici

E235
la source
4
Vous n'avez évidemment aucune idée du problème. Rien de ce que vous avez suggéré ne fonctionne. S'il vous plaît lire
n0rd