如何将数千个图像文件移动到每个有 400 个图像文件的子文件夹中?

How to move thousands of image files into subfolders each with 400 image files?

我有 2000 张图片,我想将它们移动到不同的文件夹中。每个文件夹应包含 400 张图像,并且每个文件夹位于不同的路径中。

\Desktop\images 包含:

0001.jpeg
0002.jpeg
...
2000.jpeg

应将文件移动到以下文件夹:

\Desktop\Project\Folder1\images:

0001.jpeg
0002.jpeg
...
0400.jpeg

\Desktop\Project\Folder2\images

0401.jpeg
0402.jpeg
...
0800.jpeg

\Desktop\Project\Folder3\images:

1801.jpeg
1802.jpeg
...
1200.jpeg

\Desktop\Project\Folder4\images:

1201.jpeg
1202.jpeg
...
1600.jpeg

\Desktop\Project\Folder5\images:

1601.jpeg
1602.jpeg
...
2000.jpeg

Graphical display of the folders

这是此文件移动任务的注释批处理文件,其中包含一些额外内容以使其变得有趣(对我而言):

@echo off
setlocal EnableExtensions DisableDelayedExpansion
set "SourceFolder=%UserProfile%\Desktop\images"
if not exist "%SourceFolder%\*.jpeg" goto :EOF

set "DestinationPath=%UserProfile%\Desktop\Project"
set "DestinationName=Folder"
set "FolderNameLength=6"
set "MaxFileCount=400"

setlocal EnableDelayedExpansion
set "FolderNumber=0"
set "FileCount=%MaxFileCount%"
set "DestinationFolder=!DestinationPath!\!DestinationName!"

rem Search for all non-hidden subfolders with a name starting with the
rem destination folder name and having a number append and determine
rem the greatest folder number in all existing folder names. Folder
rem names with one or more leading zeros are not supported by this code.

for /F "delims=" %%I in ('dir "!DestinationFolder!*" /AD-H-L /B 2^>nul ^| %SystemRoot%\System32\findstr.exe /I /R "^folder[0123456789][0123456789]*$"') do (
    set "FolderName=%%I"
    if !FolderName:~%FolderNameLength%! GTR !FolderNumber! set "FolderNumber=!FolderName:~%FolderNameLength%!"
)

rem Determine the number of *.jpeg files in the images folder in the folder
rem with greatest folder number if there is an existing images folder at all.

if exist "!DestinationFolder!!FolderNumber!\images\" (
    set "FileCount=0"
    for /F "eol=| delims=" %%I in ('dir "!DestinationFolder!!FolderNumber!\images\*.jpeg" /A-D /B 2^>nul') do set /A FileCount+=1
)

rem Get a list of JPEG files in source folder loaded into memory of the
rem Windows command processor ordered by name and move all these files
rem with making sure that no images folder has more than the number of
rem JPEG files as defined above. The code below is not capable moving
rem files with one or more exclamation marks because of always enabled
rem delayed expansion.

rem Note: The command DIR orders the file names strictly alphabetically
rem       and not alphanumerical as done by Windows File Explorer. So
rem       the JPEG file names should have all the same number of digits.

for /F "eol=| delims=" %%I in ('dir "!SourceFolder!\*.jpeg" /A-D /B /ON 2^>nul') do (
    set /A FileCount+=1
    if !FileCount! GTR %MaxFileCount% (
        set "FileCount=1"
        set /A FolderNumber+=1
        md "!DestinationFolder!!FolderNumber!\images"
    )
    echo Moving file "%%I" to "!DestinationFolder!!FolderNumber!\images\"
    move "!SourceFolder!\%%I" "!DestinationFolder!!FolderNumber!\images\"
    if errorlevel 1 set /A FileCount-=1
)
endlocal
endlocal

此批处理文件适用于根本不存在的目标文件夹以及一些已经存在的目标文件夹,在这种情况下,找出目标文件夹中数量最多的 JPEG 文件以确定要另外移动多少 JPEG 文件到编号最大的 FolderXimages 文件夹。

请注意 SourceFolderDestinationPathDestinationNameFolderNameLengthMaxFileCount 必须适应当地要求。

要了解使用的命令及其工作原理,请打开 command prompt window,在其中执行以下命令,并仔细阅读每个命令显示的所有帮助页面。

  • dir /?
  • echo /?
  • endlocal /?
  • findstr /?
  • goto /?
  • if /?
  • md /?
  • move /?
  • rem /?
  • set /?
  • setlocal /?

阅读有关 Using command redirection operators 的 Microsoft 文档,了解 2>nul| 的解释。重定向运算符 >| 必须在 FOR 命令行上使用脱字符 ^ 进行转义,以便在 [=78] 时被解释为文字字符 swhen =] 命令解释器在执行命令 FOR 之前处理这些命令行,该命令在后台启动的单独命令进程中执行不带或带 findstr 的嵌入式 dir 命令行%ComSpec% /c' 中的命令行作为附加参数附加。

由于您正在使用配备 的操作系统,这里有一个替代方案:

分发文件。ps1

$DesktopPath = [System.Environment]::GetFolderPath([System.Environment+SpecialFolder]::Desktop)

$SourceDir = $DesktopPath + "\images"
$FileMask = "*.jpeg"
$DestDir = $DesktopPath + "\Project"
$FilesPerDir = 400
$DestStartNum = 1

$i = 0
Get-ChildItem -Path $SourceDir -Filter $FileMask -Name | Sort-Object | ForEach-Object {
   New-Item -Path ($DestDir + "\Folder" + $DestStartNum) -Type Directory -Force > $Null
   Move-Item ($SourceDir + "\" + $_) ($DestDir + "\Folder" + $DestStartNum)
   $i++
   If ($i -Eq $FilesPerDir) {
      $DestStartNum++
      $i = 0
   }
}

为了保持与您的 标签相关的主题,您可以 运行 从命令提示符 window 该脚本,如下所示:

%SystemRoot%\System32\WindowsPowerShell\v1.0\powershell.exe -NoProfile -ExecutionPolicy RemoteSigned -File "L:\ocation\Of\DistributeFiles.ps1"

另一种方法是使用支持的 Windows 系统上已有的 PowerShell。此 cmd .bat 文件脚本运行一个 PowerShell 脚本,该脚本将使用 .jpeg 文件名的前四 (4) 位数字来确定应将其移动到哪个目录。不以四 (4) 位数字开头的文件将不会被移动。

将.bat 和.ps1 文件放在同一个目录中。当您确信将创建正确的目录并将文件移动到正确的目录时,从 mkdirMove-Item 命令中删除 -WhatIf

=== DistributeFiles.bat

@powershell -NoLogo -NoProfile -File "%~dp0%~n0.ps1"

=== 分发文件。ps1

$ProjectPath = Join-Path -Path $Env:USERPROFILE -ChildPath 'Desktop\Project';
$NFilesPerDirectory = 400;
Get-ChildItem -File -Path (Join-Path -Path $Env:USERPROFILE -ChildPath 'Desktop\images') -Filter '*.jpeg' |
    ForEach-Object {
        # Check to see if the filename starts with four (4) digits.;
        if ($_.BaseName -match '^(\d{4}).*') {
            $FolderNumber = [math]::Floor([int]$Matches[1] / $NFilesPerDirectory);
            $FolderName = 'Folder' + $FolderNumber.ToString();
            $FolderPath = Join-Path -Path $ProjectPath -ChildPath $FolderName;
            # If the destination directory does not exist, create it.;
            if (-not (Test-Path -Path $FolderPath)) { mkdir $FolderPath -WhatIf | Out-Null }
            # Move the file to the destination directory.;
            Move-Item -Path $_.FullName -Destination $FolderPath -WhatIf
        }
    }

如果由于某种原因您无法使用 .ps1 脚本文件,可以将其编码到 .bat 文件脚本中。

powershell -NoLogo -NoProfile -Command ^
    $ProjectPath = Join-Path -Path $Env:USERPROFILE -ChildPath 'Desktop\Project'; ^
    $NFilesPerDirectory = 400; ^
    Get-ChildItem -File -Path (Join-Path -Path $Env:USERPROFILE -ChildPath 'Desktop\images') -Filter '*.jpeg' ^| ^
        ForEach-Object { ^
            ^<# Check to see if the filename starts with four (4) digits.#^> ^
            if ($_.BaseName -match '^^(\d{4}).*') { ^
                $FolderNumber = [math]::Floor([int]$Matches[1] / $NFilesPerDirectory); ^
                $FolderName = 'Folder' + $FolderNumber.ToString(); ^
                $FolderPath = Join-Path -Path $ProjectPath -ChildPath $FolderName; ^
                ^<# If the destination directory does not exist, create it.#^> ^
                if (-not (Test-Path -Path $FolderPath)) { mkdir $FolderPath -WhatIf ^| Out-Null }; ^
                ^<# Move the file to the destination directory.#^> ^
                Move-Item -Path $_.FullName -Destination $FolderPath -WhatIf; ^
            }; ^
        };