Вопрос по vbscript, sorting – VBScript, как отсортировать файлы в подпапках по дате изменения (и распечатать его с абсолютным путем файла)

0

Мне нужно создать vbs для сортировки определенного количества файлов (только файлов) по дате изменения в папке с подпапками и распечатать файл с абсолютным путем, например так:

VBS:

Dim MAX
Dim Folder
MAX = 100
Folder = "C:\Test"
vbscript functions to group all files of all subfolders, and sort them by MOD date... ok
vbscript funciont to make a text file output (This i can't do it by myself)
end

Вывод текстового файла (100 новейших файлов):

c:\newest 1st file.txt
c:\subfolder1\newest 2nd file.txt
c:\subfolder7\newest 3rd file.txt
c:\subfolder2\newest 4 file.txt
c:\subfolder8\newest 5 file.txt
c:\subfolder4\newest 6 file.txt
c:\subfolder2\newest 7 file.txt
c:\newest 8 file.txt
c:\subfolder3\newest 9 file.txt
etc...

На самом деле не имеет значения, если решение может быть сделано с помощью Batch, я согласен, но я пробовал это:

Dir /S /TC /O-D

И единственная проблема в том, что мне не показывают абсолютный путь ...

EDITДа, и, конечно же, я пробовал:

Dir / B / S / TC / O-D

Но параметр / B подразумевает БОЛЬШУЮ разницу в команде, которую я говорил ранее ...

Я имею в виду:

Dir / S / TC / O-D

Команда группирует (объединяет) все файлы во всех подкаталогах и сортирует их по дате. (ХОРОШО!)

Dir / B / S / TC / O-D

Команда обрабатывает папку за папкой, упорядочивает каждый файл и показывает его. (ПЛОХОЙ!)

Так что, если мне нужно отсортировать только 100 файлов, а если я использую команду Batch dir с параметром & Bot; / B & quot; параметр, я получаю это:

Выход:

(Position 1) c:\subfolder1\Newest 1st file of this folder.txt
(Position 2) c:\subfolder1\Newest 2nd fil eof this folder.txt
(Position 3) c:\subfolder1\Old file of this folder.txt
(Position 3) c:\subfolder1\Older file of this folder.txt
(Position 4) c:\subfolder1\Oldest file of this folder.txt
(Position 5) c:\subfolder2\Newest 1st file of this folder.txt
(Position 6) c:\subfolder2\Newest 2nd file of this folder.txt
(Position 7) c:\subfolder2\Old file.txt
etc ...

Поэтому, пожалуйста, не говорите мне ничего об использовании dir с параметром / B, я знаю, это хорошо :(.

еще раз спасибо

Это несущественно, поскольку вы не можете использовать простое решение DIR - но переключатель / TW по умолчанию дает дату последнего изменения, а не / TC. Кроме того, я не вижу различий в поведении сортировки с параметром / B или без него. Оба отсортированы по папкам, а не по папкам. dbenham
Вы пробовали использовать ключ / b? ;) Bali C
Вам необходимо загрузить все пути и имена файлов вместе с DateModified в массив, отсортировать массив, а затем выполнить итерацию по массиву и вывести путь и имя файла. HK1
Если возможно, используйтеArrayList за это. Он имеет встроенную функцию сортировки. Стандартного массива в VBScript нет. Guido Gautier

Ваш Ответ

4   ответа
1

for команда и ~ синтаксис (см.for /?):

(for /r %A in (*) do @echo %~tA %A ) | sort /r

Использование скобок допускает одно перенаправление всегоfor вsort, Без брекетов каждыйecho будет перенаправлен на индивидуальныйsortтак что сортировка не будет.

РЕДАКТИРОВАТЬ: Как отметил Ekkehard.Horner, приведенный выше код будет работать только в тех регионах, где даты печатаются в формате гггг-мм-дд. В регионе, где даты печатаются в формате мм / дд / гггг, вы можете использовать следующий пакетный файл:

@Echo Off
setlocal enabledelayedexpansion

if "%1"=="list" goto :list
%0 list | sort /r

endlocal
goto :EOF

:list
for /r %%A in (*) do (
  set t=%%~tA
  echo !t:~6,4!-!t:~0,2!-!t:~3,2! %%A
)
goto :EOF

Мне не удалось повторить трюк со скобками внутри командного файла, поэтому скрипт вызывает сам себя с параметром, заставляющим его напечатать список файлов, а затем сортирует вывод. Даты конвертируются в формат гггг-мм-дд с помощью%variable~:start-length% синтаксис (см.set /?) и расширение отложенных переменных. Это не так пуленепробиваемо, как решение dbenham, но оно работает.

Error: User Rate Limit Exceeded ElektroStudios
Error: User Rate Limit Exceeded%~tAError: User Rate Limit Exceeded
Error: User Rate Limit Exceeded ElektroStudios
Error: User Rate Limit Exceededfor /fError: User Rate Limit Exceeded
Error: User Rate Limit Exceeded
1

Option Explicit

' ADO Constants needed in this demo
Const adDBTimeStamp      =        135 ' 00000087
Const adVarWChar         =        202 ' 000000CA
Const adClipString       =          2 ' 00000002

' Globals
Dim goFS   : Set goFS = CreateObject("Scripting.FileSystemObject")
Dim gsSDir : gsSDir   = "..."

' Dispatch using comments or re-order
WScript.Quit demoTraversal()
WScript.Quit demoDirWalker()
WScript.Quit demoAdoDirWalker()

' Step00: Understanding recursive traversal
Function demoTraversal()
  walkDir00 goFS.GetFolder(gsSDir)
End Function ' demoTraversal

' Minimal recursive traversal: do something for each file in folder and
' then call same Sub for each subfolder
Sub walkDir00(oDir)
  Dim oElm
  For Each oElm In oDir.Files
      WScript.Echo oElm.DateLastModified, oElm.Path
  Next
  For Each oElm In oDir.SubFolders
      walkDir00 oElm
  Next
End Sub ' walkDir00

' Step01: Recursive traversal with Class
' Use an object to abstract the 'something' action(s) and to augment
' state (count)
Function demoDirWalker()
  Dim oDirWalker : Set oDirWalker = New cDirWalker01.init()
  walkDir01 goFS.GetFolder(gsSDir), oDirWalker
  WScript.Echo oDirWalker.Count, "files seen"
End Function ' demoTraversal

Class cDirWalker01
  Private m_nCount
  Public Function init()
    Set init    = Me
    m_nCount    = 0
  End Function ' init
  Public Sub processFile(oFile)
    ' add bool expression or function to filter
    WScript.Echo oFile.DateLastModified, oFile.Path
    m_nCount = m_nCount + 1
  End Sub ' processFile
  Public Property Get Count()
    Count = m_nCount
  End Property ' Count
End Class ' cDirWalker01

Sub walkDir01(oDir, oDirWalker)
  Dim oElm
  For Each oElm In oDir.Files
      oDirWalker.processFile oElm
  Next
  For Each oElm In oDir.SubFolders
    ' add bool expression or DirWalker.method to filter
      walkDir01 oElm, oDirWalker
  Next
End Sub ' walkDir00

' Step02: Solution (POC)
Function demoAdoDirWalker()
  Dim oDirWalker : Set oDirWalker = New cAdoDirWalker.init()
  walkDir01 goFS.GetFolder(gsSDir), oDirWalker
  oDirWalker.sort "sPath ASC, dtLM ASC"
  WScript.Echo oDirWalker.getResultString()
  oDirWalker.sort "dtLM DESC, sPath ASC"
  WScript.Echo oDirWalker.getResultString()
End Function ' demoAdoDirWalker

Class cAdoDirWalker
  Private m_oRS
  Public Function init()
    Set init  = Me
    Set m_oRS = CreateObject("ADODB.Recordset")
    m_oRS.Fields.Append "dtLM" , adDBTimeStamp
    m_oRS.Fields.Append "sPath", adVarWChar, 255
    m_oRS.Open
  End Function ' init
  Public Sub processFile(oFile)
    m_oRS.AddNew
    m_oRS.Fields("sPath").Value = oFile.Path
    m_oRS.Fields("dtLM" ).Value = oFile.DateLastModified
    m_oRS.Update
  End Sub ' add
  Public Sub sort(sWhat)
    m_oRS.sort = sWhat
  End Sub ' sort
  Public Function GetResultString()
    m_oRS.MoveFirst
    GetResultString = m_oRS.GetString(adClipString, , " | ", vbCrLf, "NULL")
  End Function ' GetResultString
End Class ' cAdoDirWalker

Основная идея заключается в использовании отключенного набора записей ADO для хранения и сортировки коллекции файлов в дереве папок.

2

«Вам нужно будет загрузить весь путь и имена файлов вместе с DateModified в массив, отсортировать массив, а затем выполнить итерацию по массиву и вывести путь и имя файла», но в Пакетный файл. Программа ниже использует в качестве индекса массива YYYYMMDDHHMM Modified Time Stamp файла. Таким образом, массив сохраняетсяautomatically sorted с помощью команды Batch SET. Параметры аналогичны приведенным выше для программы dbenham: FileCount и дополнительный RootFolder.

@echo off
setlocal EnableDelayedExpansion

rem Get order of FileTimeStamp elements independent of regional settings
for /F "skip=1 tokens=2-4 delims=(-)" %%a in ('date^<NUL') do (
   set timeStampOrder=%%a %%b %%c ho mi ap
)

rem For each file in the folder given by %2 (default current one)
for /R %2 %%F in (*.*) do (
   rem Extract FileTimeStamp data (yy mm dd ho mi ap)
   for /F "tokens=1-6" %%a in ("%timeStampOrder%") do (
      for /F "tokens=1-6 delims=/-.: " %%i in ("%%~tF") do (
         set %%a=%%i
         set %%b=%%j
         set %%c=%%k
         set %%d=%%l
         set %%e=%%m
         set %%f=%%n
      )
   )
   rem Adjust hour if needed
   if !ap! equ p set /A "ho=10!ho! %% 100 + 12
   rem Create the array element with proper index
   set "file[!yy!!mm!!dd!!ho!!mi!]=%%~fF"
)

rem At this point the array is automatically sorted

rem Show the first %1 array elements
set n=0
for /F "tokens=2 delims==" %%a in ('set file[') do (
   echo %%a
   set /A n+=1
   if !n! equ %1 goto finish
)

:finish
Error: User Rate Limit Exceeded('set file[ ^| sort /r')Error: User Rate Limit Exceededif !ho!==12 set ho=00Error: User Rate Limit Exceeded!Error: User Rate Limit Exceeded!Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded!Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded ElektroStudios
2

которое использует только собственные команды - и на самом деле оно работает хорошо :-)

Я не уверен, могут ли быть дополнительные символы, которые должны быть экранированы в команде WMIC, поскольку у меня нет большого опыта работы с WMIC. Но в остальном я думаю, что это довольно пуленепробиваемое.

::treeNewestFiles FileCount [RootFolder]
::
::  Searches the directory tree rooted at RootFolder and prints
::  the most recently modified files. The number of files printed
::  is limited to a maximum of FileCount. If RootFolder is not
::  specified then the root is the current directory.
::
@echo off
setlocal disableDelayedExpansion

::define base temp file name
set "tempFile=%temp%\fileDates%random%.txt"

::Loop through all folders rooted at %2 (current directory if not specified), and use
::WMIC to list last modified timestamp and full path of each file in each folder.
::The last modified timestamp is in UTC ISO 8601 format, so it sorts properly.
(
  for /r %2 %%F in (.) do (
    set "folder=%%~pnxF"
    set "drive=%%~dF"
    setlocal enableDelayedExpansion
    2>nul wmic datafile where (path='!folder:\^=\\!\\' and drive='%%~dF'^) get lastmodified, name
    endlocal
  )
)>"%tempFile%"

::Convert unicode to ansii
type "%tempFile%" >"%tempFile%2"

::Preserve only data rows
findstr "^[0-9]" "%tempFile%2" >"%tempFile%3"

::Sort the results in descending order
sort /r "%tempFile%3" >"%tempFile%4"

::Print first %1 files in results
set n=0
for /f "usebackq tokens=1*" %%A in ("%tempFile%4") do (
  echo %%B
  set /a &,quot;n+=1, 1/(%1-n)" 2>nul || goto finish
)

:finish
del "%tempFile%*"

New faster version

Мой оригинальный код сделал новый вызов WMIC для каждого каталога. Инициализация WMIC занимает значительное время при каждом вызове. Я сократил время выполнения на 45%, создав скрипт команд и вызывая WMIC только один раз. Количество прироста производительности зависит от количества каталогов в дереве. Чем больше каталогов, тем больше поможет эта новая версия. Я уверен, что при переходе на VBS можно добиться еще большего прироста производительности, но я не думаю, что это стоило бы усилий. Я считаю, что этот процесс сейчас в значительной степени оптимизирован.

::treeNewestFiles FileCount [RootFolder]
::
::  Searches the directory tree rooted at RootFolder and prints
::  the most recently modified files. The number of files printed
::  is limited to a maximum of FileCount. If RootFolder is not
::  specified then the root is the current directory.
::
@echo off
setlocal disableDelayedExpansion

::define temp folder for temp files
set "tempFolder=%temp%\fildates%random%"
md "%tempFolder%"

::define base path\name for temp files
set "tempFile=%tempFolder%\tempFile.txt"

::Loop through all folders rooted at %2 (current directory if not specified),
::and build a script of WMIC commands that will list last modified timestamps
::and full path of files for each folder. The last modified tamestamp will
::be in ISO 8601 format, so it sorts properly.
(
  echo /append:"%tempFile%1"
  for /r %2 %%F in (.) do (
    set "folder=%%~pnxF"
    set "drive=%%~dF"
    setlocal enableDelayedExpansion
    echo datafile where (path='!folder:\^=\\!\\' and drive='%%~dF'^) get lastmodified, name
    endlocal
  )
  echo quit
)>"%tempFile%"

::Execute the WMIC script
::WMIC creates a temporary file in current directory,
::so change directory 1st so it doesn't interfere with results.
pushd "%tempFolder%"
cmd /c ^<"%tempFile%" wmic ^>nul 2^>nul

::Convert unicode to ansii
type "%tempFile%1" >"%tempFile%2"

::Preserve only data rows
findstr "^[0-9]" "%tempFile%2" >"%tempFile%3"

::Sort the results in descending order
sort /r "%tempFile%3" >"%tempFile%4"

::Print first %1 files in results
set n=0
for /f "usebackq tokens=1*" %%A in ("%tempFile%4") do (
  echo %%B
  set /a "n+=1, 1/(%1-n)" 2>nul || goto finish
)

:finish
popd
rd /q /s "%tempFolder%"
Error: User Rate Limit Exceeded ElektroStudios
Error: User Rate Limit Exceeded ElektroStudios
Error: User Rate Limit Exceeded ElektroStudios
Error: User Rate Limit Exceeded

Похожие вопросы