4

У меня есть сотни файлов с путями длиннее 260 символов, которые я хочу переименовать. Используя Powershell, я могу найти длинные имена, используя cmd /c dir /s /b |? {$_.length -gt 260} , но фактические командлеты не поддерживают длинные имена файлов: Get-Item возвращает

"не могу найти путь [длинный путь], потому что он не существует"

Я читал, что модуль с именем NTFSSecurity может работать с длинными путями, но до сих пор я знаю, что он может перечислять файлы только с помощью командлета Get-ChildItem2. Я до сих пор не знаю, как на самом деле переименовать файлы таким образом.

Вне Powershell я нашел инструмент под названием TLPD, который может перечислять файлы, но это все.

До сих пор мне удавалось справиться с этим только путем ручного переименования родительских папок, чтобы путь становился достаточно коротким для доступа (возможно, я смогу эмулировать этот процесс с помощью Powershell - но я бы оценил более простой способ)

Изменить: чтобы уточнить, я хотел бы сохранить файлы, а не удалять их как можно больше.

4 ответа4

2

Я написал сценарий, который работал. Спасибо jftuga за предложение.

# This script searches through the search_path, finds file paths that are longer than total_path_length_threshold, and truncates the filename

### user settings ###

$test_run = $true                   # set to $false to start renaming for real
$search_path = "C:\my_folder\"      # the path to search for long names
$total_path_length_threshold = 260  # the length threshold to test
$characters_to_truncate = 5         # the number of characters to strip from the end of long filenames (a new identifier will also be added)
$log_file_path = "c:\my_folder\long_filename_log.txt"  # log file location

$virtual_drive = "v:"               # used for temporary processing using subst. Must look like "v:" and not like "v:\"

### end of user settings ###

Out-File $log_file_path
"Test run = $test_run" | Tee-Object $log_file_path -Append
"search_path = $search_path " | Tee-Object $log_file_path -Append
"total_path_length_threshold = $total_path_length_threshold " | Tee-Object $log_file_path -Append
"characters_to_truncate = $characters_to_truncate " | Tee-Object $log_file_path -Append

$counter = 0  # counter for creating new unique filenames
$collection = cmd /c dir $search_path /s /b |? {$_.length -gt $total_path_length_threshold }
$count_paths = ($collection | measure).count - 1

foreach ($path in $collection) {
    echo "found long path: $path"

    # get the parent's path
    $parent_path = Split-path -path $path

    # mount the parent to a virtual drive
    subst $virtual_drive $parent_path

    # get leaf element
    $leaf = split-path -leaf $path

    # make new short path
    $short_virtual_path = join-path $virtual_drive $leaf

    # get the long-name item 
    $item = Get-Item -LiteralPath $short_virtual_path

    if ($item -is [System.IO.fileinfo]) {
        # log long filename path
        "item $counter : Long filename path: $path" | Out-File $log_file_path -Append

        $filename = $item.name  #get the full filename

        # get filename extension
        $filename_extension = $item.Extension

        # get filename without extension:
        $basename = $item.BaseName    
        $basename_length = $basename.length 

        # give the new filename a unique index, to avoid duplicate filenames
        $new_index = "X" + $counter + "X"
        # the actual number of characters to cut is characters_to_truncate + new_index length
        $adjusted_characters_to_truncate = $characters_to_truncate + $new_index.length 

        if ( $basename_length -gt $adjusted_characters_to_truncate ) {
            $length_to_use = $basename_length - $adjusted_characters_to_truncate

            # shorten the filename by truncating it by specified num of char
            $new_filename = $basename.substring(0, $length_to_use ) + $new_index + $filename_extension

            # log the new filename path
            $new_path = $parent_path + $new_filename
            "item $counter : new filename path: $new_path " | Out-File $log_file_path -Append

            if (!$test_run) {
                # rename the file

                Rename-Item -LiteralPath $short_virtual_path $new_filename
            }

        }

    }

    $counter = $counter + 1

    #unmount the virtual drive
    subst v: /d
}

"Found $count_paths paths." | echo 
1

Так вы можете удалять папки и файлы с очень длинными путями, хотя и не в PowerShell.

mkdir c:\alfa\bravo\charlie\delta\echo\foxtrot\golf\hotel\india\julliett\kilo\lima\mike\november\oscar\papa\quebec\romeo\sierra\tango\uniform\victor\whiskey\xray\yankee\zulu

join j: c:\alfa\bravo\charlie\delta\echo\foxtrot\golf\hotel\india\julliett
j:
subst k: j:\kilo\lima\mike\november\oscar\papa\quebec\romeo\sierra
k:
subst l: k:\tango\uniform\victor\whiskey
l:
rd /s/q xray
k:
rd /s/q tango
j:
rd /s/q kilo
c:
rd /s/q alfa

subst l: /d
subst k: /d
subst j: /d

Общая концепция состоит в том, чтобы объединить несколько команд subst чтобы они глубоко встраивались в структуру папок. Возможно, вам придется идти около 6 букв глубиной. Затем вы можете начать удаление папок с самого глубокого уровня, а затем пройти путь назад и обратно по пути. После этого вы можете удалить буквы дисков, созданные с помощью команды subst .

0

Есть эта классная утилита для работы с узлами, которая будет выполнять работу под названием rimraf.Если у вас уже установлен узел, просто установите его через npm

npm install -g rimraf
Использование: rimraf dir

Также вы можете использовать robocopof, который может создавать пути длиннее, чем ограничение в 260 символов, а также может удалять их

см. страницу Robocopy

Установите его со страницы Microsoft

0

Чтобы удалить пути с помощью robocopy, вы можете использовать параметр /purge для пустой директории.

Пример CMD:
Robocopy.exe C:\temp\SourceDir C:\Temp\EmptyDir /Purge

Здесь SourceDir - это каталог, который нужно удалить.

Это может быть в паре с PowerShell довольно легко

Пример PowerShell:

$Paths = Get-Content C:\Temp\DeleteDirectories
ForEach($Path in $Paths){
   Robocopy.exe $Path C:\Temp\EmptyDir /Purge
           }

Это перебирает все пути, которые вы C:\Temp\DeleteDirectories и удаляет их.

Надеюсь это поможет!

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .