【问题标题】:Windows Batch Script for moving files to different Folders based on File Name for Huge Data Volume用于基于文件名将文件移动到不同文件夹的 Windows 批处理脚本,用于大数据量
【发布时间】:2019-06-28 17:41:43
【问题描述】:

我有大约 180K 文件需要根据文件名移动到文件夹中。 文件具有不同的扩展名。我需要获取所有以数字开头的文件名并获取数字直到第一个'-'并创建一个文件夹。移动文件夹中带有编号的所有文件。 需要排除不以数字开头的文件。

示例数据:文件名

123-ACBDHDJ.pdf

123-dhdjd.txt 

5658-dgdjdk.txt

456477-gse.docx

例如;根据上面文件名中提到的上述数据,我想做以下事情:

  • 制作文件夹1235658456477
  • 移动文件夹 123 中的前两个文件,文件夹 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. 脚本运行时间过长,性能很慢。数据量为 非常高,18 万条记录。

请为此提供批处理脚本或任何更快的方法来执行此操作,因为数据量非常巨大。提前致谢。

【问题讨论】:

  • 你试过什么,你卡在哪里了?请分享您的编码尝试并准确描述您遇到的问题!阅读tour 以及这些帮助文章:How to Askminimal reproducible example。目前,您的“问题”只不过是一个代码请求,这显然是题外话!谢谢!提示:for loopfor /Fmkdirmove
  • 添加了尝试过的代码和面临的问题。
  • 还有很多不必要的for循环,你循环每个扩展类型,但最终做所有扩展?此外,您从不测试数字,那么如果文件名为 test-file.eml 怎么办?
  • 您应该考虑接受答案。

标签: windows batch-file cmd


【解决方案1】:

让我们考虑一下为什么需要很长时间。您有 128k 个文件,运行 4 个循环,这意味着 for 循环自己处理每个文件 5 次,即 640 000 个进程,然后您为每个运行 echos,即更多进程,然后我们检查如果一个文件夹存在并且如果不创建它,则该文件夹存在是另一个过程。我猜你正在得到我要去的地方。您实际上正在运行超过一百万个过程来完成此任务。

也许我们摆脱所有不需要的 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

至于名称和扩展名部分,设置后你永远不会使用它们,如果你仍然想在某个地方使用文件的名称和扩展名,那么你只需使用它们而无需设置vars:

@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

【讨论】:

    【解决方案2】:

    您使用了很多不必要的代码,这使您的批处理文件太慢了。我会建议类似:

    @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等。查看 cmd 中for /? 的输出。

    【讨论】:

      【解决方案3】:

      您可能已经有了 .bat 文件脚本的答案。这是在 PowerShell 中执行此操作的一种方法。当脚本经过测试并将正确移动文件时,请从 Move-Item cmdlet 中删除 -WhatIf

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

      这可以通过将脚本保存到文件 (thefile.ps1) 并使用以下命令或将命令放入 .bat 文件脚本中来从 cmd shell 运行。

      powershell -NoLogo -NoProfile -File thefile.ps1
      

      【讨论】:

      • 要通过 PowerShell 从 cmd shell 作为 -File 运行脚本,您可能需要设置执行策略。
      【解决方案4】:

      我会这样做——查看代码中的所有解释性备注(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
      

      在测试脚本的正确输出后,删除两个大写的ECHO 命令!

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2011-04-05
        • 1970-01-01
        • 2013-11-17
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多