Пакетный сценарий Windows для перемещения файлов в разные папки на основе имени файла для огромного объема данных - PullRequest
0 голосов
/ 05 февраля 2019

У меня есть около 180К файлов, которые необходимо переместить в папки на основе имени файла.Файлы имеют разные расширения.Мне нужно взять все имена файлов, которые начинаются с цифр, получить номер до первого «-» и создать папку.Переместите все файлы с номером в папке.Необходимо исключить файлы, которые не начинаются с цифр.

Пример данных: имена файлов

123-ACBDHDJ.pdf

123-dhdjd.txt 

5658-dgdjdk.txt

456477-gse.docx

Например;Основываясь на вышеупомянутых данных, упомянутых выше в именах файлов, я хочу сделать следующее:

  • сделать папки 123 , 5658 и 456477
  • Перемещение первых двух файлов в папке 123, 3-го файла в папке 5658 и последнего файла в папке 456477.

Пробный сценарий:

@echo off
setlocal enabledelayedexpansion
for %%A in (*.psd *.jpg *.html *.tif *.xls *.xlsx *.htm *.csv *.pdf *.docx *.TXT *.zip *.msg *.xlsb *.eml *.*) do (
   echo file found  %%A
   for /f "delims=" %%B in ("%%A") do set fname=%%~nB
   for /f "delims=" %%C in ("%%A") do set fextn=%%~xC
   for /f "tokens=1* delims=-" %%D in ("!fname!") do set folname=%%D
   echo folder name !folname!
   if not exist "!folname!" (
      echo Folder !folname! does not exist, creating
      md "!folname!"
   ) else (
      echo Folder !folname! exists
   )
   echo Moving file %%A to folder !folname!
   move "%%A" "!folname!"
   )
echo Finished
pause

Проблемы, с которыми в данный момент сталкиваются:

  1. Папки, созданные с буквенно-цифровыми символами, я хотел игнорировать эти файлы и выбирать только те, которые начинаются с цифр.
  2. Сценарий выполняется слишком долго, очень низкая производительность.Объем данных очень большой, 180 тыс. Записей.

Пожалуйста, помогите с пакетным скриптом для этого или любого более быстрого способа сделать это, поскольку объем данных очень велик.Заранее спасибо.

Ответы [ 4 ]

0 голосов
/ 05 февраля 2019

Я бы сделал это следующим образом - см. Все пояснительные замечания (rem) в коде:

@echo off
setlocal EnableExtensions DisableDelayedExpansion

rem // Define constants here:
set "_ROOT=%~dp0." & rem /* (directory containing all the files; `%~dp0` points to the
                     rem     parent directory of this batch script; to use the current
                     rem     working directory, simply specify a single `.`) */
set "_MASK=?*-*.*" & rem /* (search pattern to find files, matching only files with at
                     rem     least one hyphen in their names) */
set "_FILTER=^[0123456789][0123456789]*-" & rem /* (`findstr` filter expression;
                     rem     this matches only files whose name begin with one or more
                     rem     decimal digits followed by a hyphen) */

rem // Change to given root directory:
pushd "%_ROOT%" && (
    rem // Loop through all matching files:
    for /F "tokens=1* delims=-" %%E in ('
        rem/ Return files and filter out those with non-numeric prefix: ^& ^
            dir /B /A:-D "%_MASK%" ^| findstr /R /I /C:"%_FILTER%"
    ') do (
        rem // Try to create target directory:
        ECHO md "%%E" 2> nul
        rem // Move file into target directory:
        ECHO move /Y "%%E-%%F" "%%E\"
    )
    rem // Return from root directory:
    popd
)

endlocal
exit /B

После проверки правильности вывода сценария, удалите оба верхних-case ECHO команды!

0 голосов
/ 05 февраля 2019

Давайте рассмотрим, почему это занимает много времени.У вас есть 128k файлов, вы запускаете 4 цикла, то есть сами циклы for обрабатывают каждый файл 5 раз, то есть 640 000 процессов самостоятельно, затем вы запускаете echo s для каждого, то есть еще больше процессов, затем мы проверяемесли папка существует и, если ее не создать, папка существует, это другой процесс.Вы фактически выполняете более миллиона процедур для выполнения этой задачи.

Может быть, мы избавимся от всех нежелательных циклов for, используем * вместо именования каждого файла, а затем избавимся от отложенного расширения, поскольку мы можем простобез необходимости устанавливать переменные:

@echo off
for %%i in (*) do (
    echo file found  %%i
    for /f "tokens=1* delims=-" %%a in ("%%i") do (
     if "%%a-%%b"=="%%i" (
      md %%a>nul
      move "%%~fi" %%a
   )
  )
 )
echo Finished
pause

Что касается части имени и расширения, вы никогда не будете использовать их после установки. Если вы все еще хотите где-то использовать имя и расширение файлов, тогда вы простоиспользуйте их без необходимости устанавливать переменные:

@echo off
for %%i in (*) do (
   echo file found  %%i
   for /f "tokens=1* delims=-" %%a in ("%%i") do (
    if "%%a-%%b"=="%%i" (
       md %%a>nul
       move "%%~fi" %%a
       echo This is the file extension: %%~xi
       echo This is the filename: %%~na
       echo This is the filename, drive and path: %%~dpi
       echo This is the filename with full path: %%~fi
   )
  )
 )
echo Finished
pause
0 голосов
/ 05 февраля 2019

Возможно, у вас уже есть ответ с использованием скриптов .bat.Вот способ сделать это в PowerShell.Когда сценарий протестирован и будет правильно перемещать файлы, удалите -WhatIf из командлета Move-Item.

$sourcedir = './s'
$destdir = './d'

Get-ChildItem -File -Path "$sourcedir/*" |
    ForEach-Object {
        if ($_.Name -match '^(\d+)-.*') {
            $ddir = Join-Path $destdir $Matches[1]
            if (-not (Test-Path -Path $ddir)) { New-Item -Name $ddir -ItemType Directory }
            Move-Item -Path $_.FullName -Destination $ddir -WhatIf
        }
    }

Это можно запустить из оболочки cmd, сохранив сценарий в файл (thefile.ps1) и используя следующую команду или поместив команду в скрипт файла .bat.

powershell -NoLogo -NoProfile -File thefile.ps1
0 голосов
/ 05 февраля 2019

Вы используете много ненужного кода, что делает ваш пакетный файл слишком медленным.Я бы предложил что-то вроде:

@echo off

for %%A IN (*.*) do (
    if not "%%~fA" == "%~f0" (
        echo File found: %%A
        for /f "tokens=1* delims=-" %%B IN ("%%~nxA") do (
            md %%B>nul
            (move "%%~fA" "%%~dpA%%B")>nul
        )
    )
)
echo Finished
pause
exit /b %errorlevel%

Кажется также, что другие циклы, которые вы делаете, бесполезны.Вы можете напрямую использовать %%~nA, %%~xA и т. Д. См. Вывод for /? в cmd.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...