Powershell一次递归移动20,000个文件

Powershell recursively move 20,000 files at a time

我是 Powershell 的新手。我正在尝试将要处理的数据移动到其他地方,而这些地方对一次可以处理的文件数量有限制。我的源文件夹有数百个子文件夹,每个子文件夹又可能有多达 100 个子文件夹,总共有数百万个小文件。假定文件名是导出的唯一 25 位数字输出,因此如果排除检查可加快整个过程,则无需在每次移动时检查现有文件名。

我想使用 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[=17=]0001 [20,000 messages] D:\My20kFiles[=18=]0002 [next 20,000 messages] D:\My20kFiles[=19=]0003 [next 20,000 messages] ...etc

列出文件,将它们移动到名为 (counter++ / 20000) 的文件夹中。

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

未经测试。嗯。 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--
    }

}

自动生成 PS 来自我的代码块的帮助链接(如果可用):

以下脚本可测试并执行以下任务:

检查目标文件夹是否为空,如果不是则退出。

将移动文件操作记录到名为 log.txt 的文件以供稍后查看。

可以在测试模式下工作,提前知道会发生什么。

可以定义源文件夹-目标文件夹-增量值

   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[=12=]0001  at counter=1
    mv I:\myfiles.txt  i:\My20kFiles[=12=]0001
    mv I:\myfiles.txt  i:\My20kFiles[=12=]0001
    mv I:\myfiles.txt  i:\My20kFiles[=12=]0001
    mv I:\myfiles.txt  i:\My20kFiles[=12=]0001
    mv I:\myfiles.txt  i:\My20kFiles[=12=]0001
    Creating new folder i:\My20kFiles[=12=]0002  at counter=6
    mv I:\myfiles.txt  i:\My20kFiles[=12=]0002
    mv I:\myfiles.txt  i:\My20kFiles[=12=]0002
    mv I:\myfiles.txt  i:\My20kFiles[=12=]0002
    mv I:\myfiles.txt  i:\My20kFiles[=12=]0002
    mv I:\myfiles.txt  i:\My20kFiles[=12=]0002
    Creating new folder i:\My20kFiles[=12=]0003  at counter=11
    mv I:\myfiles.txt  i:\My20kFiles[=12=]0003
    mv I:\myfiles.txt  i:\My20kFiles[=12=]0003
    .................

更新:

我修改了代码: 添加日志文件作为参数。默认路径将是当前的 powershell 工作文件夹

$Testmode 最初是假的,所以你移动文件。您可以在测试模式下将参数 $Testmode=$true 传递给 运行(不移动到文件),您可以查看描述文件移动位置的日志文件。

您可以根据需要自定义代码

试试这个

 $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 }