2016-10-26 13 views
1

Я новичок в Powershell. Я пытаюсь переместить данные, которые будут обрабатываться в другом месте, которые имеют ограничения на количество файлов одновременно. Моя исходная папка содержит сотни подпапок, каждая из которых, в свою очередь, также может иметь до 100 подпапок, в общей сложности до миллионов небольших файлов. Предполагается, что имена файлов являются уникальными 25-значными выводами из экспорта, поэтому проверка существующих имен файлов при каждом перемещении не требуется, если исключить проверку скорости в общем процессе.Powershell рекурсивно перемещает 20 000 файлов за один раз

Я хотел бы автоматизировать перемещение (не копирование) их с помощью Powershell из исходного пути в инкрементную папку назначения по 20 000 файлов каждый. Имена папок выходных папок не важны, если у каждого из них не более 20 000 файлов в каждом месте назначения и не перекрываются имена существующих папок.

Пример:

Источник: C: \ MyFiles имеет 100 подпапок, что каждый из них также имеют 100 подпапок.

C:\Myfiles\Folder000\Folder000A\file1.txt C:\Myfiles\Folder000\Folder000A\file2.txt C:\Myfiles\Folder000\Folder000A\file3.txt C:\Myfiles\Folder000\Folder000B\file1.txt C:\Myfiles\Folder000\Folder000B\file1.txt C:\Myfiles\Folder001\Folder000A\file1.txt ...etc

Направление D: \ My20Kfiles

D:\My20kFiles\000001 [20,000 messages] D:\My20kFiles\000002 [next 20,000 messages] D:\My20kFiles\000003 [next 20,000 messages] ...etc

+0

ли eyou получить представление о том, когда вы выполняете 'GCI | выбрать -first 10' ;-) – LotPings

+0

правой, но как я могу цикл через который выводит одну строку за раз, чтобы переместить ее в пункт назначения? Я знаю, что могу получить полный путь к выходу на экран с помощью -first, как get-ChildItem -recurse -Filter * .txt -file | выберите -first 10000 | % {$ _. FullName} –

+1

Чтобы уточнить: с файлом _flattening_ вы идете в иерархии ввода при перемещении файлов в целевые папки? Это противоречит вашим образцовым данным, у которых есть уникальные имена файлов, такие как 'file1.txt' – mklement0

ответ

0

попробовать это

$yourdir="C:\MyFiles" 
$yourdestdir="D:\My20Kfiles" 
$loop=20000 
$i=$loop; 
gci $yourdir -Recurse -File -Filter *.txt | %{$newdir="$yourdestdir\{0:d6}\" -f [math]::DivRem($i++, $loop, [ref]$null) ;new-item -Path $newdir -Force -ItemType Directory; Move-Item -Path $_.FullName -Dest $newdir -Force } 
+0

Ran и мгновенно вернулся в приглашение без вывода и, казалось, не предпринимал никаких действий в папке с копией тестового образца, используемой для $ yourdir –

+0

У вас есть файлы .txt в вашем каталоге C: \ MyFiles? он работает над моим тестом – Esperento57

+0

И была моя ошибка, которую я забыл исправить расширение! Спасибо, это сработало отлично! –

2

Перечислите файлы, переместите их в папку с именем (counter ++/20000).

gci "c:\myfiles" -R -File | mv -Dest {"c:\My20kFiles\{0:d6}\" -f [math]::DivRem($global:counter++, 20000, [ref]$null)} -Force -WhatIf 

Непрошеный. YMMV. mv создаст папки с -Force. Удалите -WhatIf, чтобы сделать его фактически запущенным.

Он фактически не проверяет наличие файлов 20k в папке или перекрывает ли существующие имена папок. Но принцип, я думаю.

Также не проверен, он пытается поместить файлы 20k в папку, а затем перейти к следующему номеру неиспользуемой папки.

$FolderNumber = 0 
$FilesRemainingForThisFolder = 0 

Get-ChildItem "c:\myfiles" -Recurse -File | ForEach-Object { 

    if (0 -eq $FilesRemainingForThisFolder) 
    { 
     # Keep counting foldernumber until we get to a folder name that doesn't exist. 
     do { 
      $FolderNumber++ 
      $DestinationFolder = "c:\My20kFiles\{0:d6}\" -f $FolderNumber 
     } while ((Test-Path $DestinationFolder)) 

     mkdir $DestinationFolder 
     $FilesRemainingForThisFolder = 19999 
    } 
    else 
    { 
     Move-Item -LiteralPath $_.FullName -Destination $DestinationFolder -Force -WhatIf 
     $FilesRemainingForThisFolder-- 
    } 

} 

Auto сгенерированные PS помогают ссылки из моего кодоблок (если таковые имеются):

+1

Красиво сделано; не знал об трюке pass-a-script-block-as-a-parameter-value-rated-with-the-current-pipe-object-as-a-parameter. (Где это документировано?) Я предлагаю '[Math] :: Floor()' в качестве более простой альтернативы '[Math] :: DivRem()' (по крайней мере в этом случае для положительных результатов, если нет необходимости остаток). – mklement0

+0

@ mklement0 Знаете ли вы об этом в контексте 'sort-object'? например 'gci | sort -property {$ _. substring (3,5)} 'для сортировки файлов по части имени? Я не знаю, где это задокументировано, хотя это сообщение в блоге - https://learn-powershell.net/2014/10/11/using-a-scriptblock-parameter-with-a-powershell-function/ - MVP Dave Wyatt, в комментариях, говорит, что он плохо документирован и говорит о том, как он работает. Редактировать: блоги Джеффри Сновера, которые здесь происходят: https://blogs.msdn.microsoft.com/powershell/2006/06/23/flexible-pipelining-with-scriptblock-parameters/ – TessellatingHeckler

+0

Спасибо, что поделились этим, здесь '- ea sil..' необходим и увидеть эффект 'gci | sort -property {$ _. Name.substring (1,1)} -ea silentlycontinue' – LotPings

0

Следующий сценарий является проверяемым и выполнить следующие задачи:

Проверьте, если целевая папка пуста, выход, если это не так.

Запишите действие движущихся файлов в файл с именем log.txt, который будет рассмотрен последним.

Может работать в тестовом режиме, чтобы заранее знать, что произойдет.

Вы можете определить папку источника -target папку - значение приращения

function Move-Files { 
    param ($Source ,$Targert,$Increment=5 , $TestMode, $Logfile) 

     $currentpath=pwd 
     if (!$LogFile) {$Logfile= "{0}\{1}" -f $currentpath,"log.txt" } 
     "log file is created in $logfile" 
     # check that destination folder is empty and create 
     if(!(Test-Path -Path $Targert)){ 
        $null=New-Item -ItemType directory -Path $Targert -Force 
      } 
     else 
     { 
      $targetFiles = get-childitem $Targert -Recurse -File 
      if ($targetFiles -ne $null) {"Target folder not empty, Please remove it";return} 
     } 


     $files=get-childitem $source -Recurse -File  
     $fileCounter=0 
     $folderCounter=0 
     $Nextfolder="00001" 
     "Moving {0} to {1}| Total Files: {2} | Increment:{3}" -f $Source, $Targert , $files.count,$increment |tee $Logfile 
     $files |foreach { 
      $fileCounter++ 
      if ((($fileCounter - 1) % $increment) -eq 0) 
      { 
       $folderCounter++ 
       $Nextfolder= "{0}\{1}" -f $targert, $folderCounter.ToString("000000")  
       "Creating new folder {0} at counter={1}" -f $Nextfolder,$fileCounter |tee -Append $Logfile 
       #create Folder 
       $null=New-Item -ItemType directory -Path $Nextfolder -Force 

       } 
       if ($testMode) 
       { 
       "mv {0} {1}" -f $_.FullName,$Nextfolder |tee -Append $Logfile 
       } 
       else 
       { 

       mv $_.FullName -Destination $Nextfolder -Force #-WhatIf 
       "mv {0} {1}" -f $_.FullName,$Nextfolder |tee -Append $Logfile 
       } 
     } 
    } 

Как использовать:

$source="i:\myfiles" 
    $targert="i:\My20kFiles" 
    $increment=5 # for a test, modify 20000 

    #run in test mode to know what will happen 
    $TestMode=$true # modify to $flase to actual moving files 

    Move-Files -Source $source -Targert $targert -Increment $increment -TestMode $TestMode 

Пример вывода: (вы найдете то же самое в файле журнала log.txt)

Moving i:\myfiles to i:\My20kFiles| Total Files: 42 | Increment:5 
    Creating new folder i:\My20kFiles\000001 at counter=1 
    mv I:\myfiles\1.txt i:\My20kFiles\000001 
    mv I:\myfiles\10.txt i:\My20kFiles\000001 
    mv I:\myfiles\11.txt i:\My20kFiles\000001 
    mv I:\myfiles\12.txt i:\My20kFiles\000001 
    mv I:\myfiles\13.txt i:\My20kFiles\000001 
    Creating new folder i:\My20kFiles\000002 at counter=6 
    mv I:\myfiles\14.txt i:\My20kFiles\000002 
    mv I:\myfiles\15.txt i:\My20kFiles\000002 
    mv I:\myfiles\16.txt i:\My20kFiles\000002 
    mv I:\myfiles\17.txt i:\My20kFiles\000002 
    mv I:\myfiles\18.txt i:\My20kFiles\000002 
    Creating new folder i:\My20kFiles\000003 at counter=11 
    mv I:\myfiles\19.txt i:\My20kFiles\000003 
    mv I:\myfiles\2.txt i:\My20kFiles\000003 
    ................. 

Обновление:

Я изменил код: Добавить файл журнала как параметр. Путь по умолчанию будет текущей рабочей папкой powershell.

$ Testmode изначально ошибочно, поэтому вы перемещаете файлы. Вы можете передать параметр $ Testmode = $ true для запуска в тестовом режиме (не перемещаясь к файлам), и вы можете просмотреть файл журнала, в котором описывается, куда будут перемещаться файлы.

Вы можете настроить код, как вы хотите

+0

Сглаживание 20-килобайтных файлов в новую отдельную папку для каждого набора - это результат, который я хотел бы иметь. Благодарим вас за варианты - я буду пытаться обе эти примеры и вернусь с результатами в ближайшее время. –

+0

Возможно, я неправильно использую ваш код. Я сохранил его и выполнил с переменными, установленными в скрипт, и выполнил с аргументами, и не получил выход, и нет log.txt. –

+0

. Файл log.txt создается по пути ISE по умолчанию. Вы можете определить путь, например, c: \ temp \ log.txt. Установите $ testmode = $ false для перемещения файлов. если $ testmode = $ true (по умолчанию) не перемещается в файлы, а файл log.txt создается с сообщениями, описывающими файлы, перемещающими источник и сумму. Попробуйте и дайте мне знать результат. –