una programa procedimiento por para organizar ordenar ordenan los gusto fisicas fecha digitales dentro cómo convencional como carpetas carpeta archivos sorting vbscript batch-file directory

sorting - programa - vbscript cómo ordenar los archivos en subcarpetas por fecha de modificación(e imprimirlo con la ruta absoluta del archivo)



programa para organizar archivos y carpetas (4)

Una demostración de tres pasos para que comiences:

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

La idea principal es usar un conjunto de registros ADO desconectado para almacenar y ordenar la colección de archivos en un árbol de carpetas.

Necesito crear un vbs para ordenar una cantidad fija de archivos (solo los archivos) por la fecha modificada en una carpeta con subcarpetas, e imprimir el archivo con la ruta absoluta, como esta:

El 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

El resultado del archivo de texto (100 archivos más nuevos):

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...

Realmente no importa si la solución se puede hacer con Batch, estoy de acuerdo, pero he intentado esto:

Dir /S /TC /O-D

Y el único problema es que no me muestren el camino absoluto ...

EDITAR : Ah, y por supuesto que he intentado:

Dir / B / S / TC / O-D

Pero el parámetro / B implica una GRAN diferencia en el comando que dije antes ...

Quiero decir:

Dir / S / TC / O-D

El comando agrupa (juntos) todos los archivos en todos los subdirectorios y los ordena por fecha. (¡BUENO!)

Dir / B / S / TC / O-D

El comando va procesando carpeta por carpeta y ordenando cada archivo, y mostrándolo. (¡MALO!)

Entonces, si necesito ordenar neswest solo 100 archivos, y si uso el comando Batch dir con el parámetro "/ B", obtengo esto:

Salida:

(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 ...

Así que por favor no me digas nada sobre usar dir con el parámetro / B, lo sé bien :(.

gracias de nuevo


Aquí hay una solución de lote puro que usa solo comandos nativos, y en realidad funciona bien :-)

No estoy seguro de si podría haber caracteres adicionales que deban escaparse en el comando WMIC, ya que no tengo mucha experiencia con WMIC. Pero de lo contrario, creo que es bastante a prueba de balas.

::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 "n+=1, 1/(%1-n)" 2>nul || goto finish ) :finish del "%tempFile%*"

Nueva versión más rápida

Mi código original realizó una nueva llamada a WMIC para cada directorio. A WMIC le lleva una cantidad significativa de tiempo inicializarse con cada llamada. Reduje el tiempo de ejecución en un 45% construyendo un script de comandos y llamando a WMIC solo una vez. La cantidad de ganancia de rendimiento es una función de la cantidad de directorios en el árbol. Cuanto mayor sea el número de directorios, más ayudará esta nueva versión. Estoy seguro de que aún se obtendrán más mejoras de rendimiento al convertir a VBS, pero no creo que valga la pena el esfuerzo. Creo que este proceso ahora está bastante optimizado.

::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%"


Puedes hacerlo con comandos y ~ sintaxis (ver for /? ):

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

El uso de corchetes permite una sola redirección od entero for sort . Sin saltos, cada echo se redirigiría a una sort individual, por lo que no se realizaría ninguna clasificación.

EDITAR: Como señaló Ekkehard.Horner, el código anterior funcionará solo en regiones donde las fechas se imprimen en formato aaaa-mm-dd. En una región donde las fechas se imprimen en formato mm / dd / aaaa, puede usar el siguiente archivo por lotes:

@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

No logré repetir el truco con corchetes dentro de un archivo por lotes, por lo que el script se llama a sí mismo con un parámetro que hace que imprima la lista de archivos y luego ordena la salida. Las fechas se convierten al formato aaaa-mm-dd utilizando %variable~:start-length% sintaxis (ver set /? ) Y la expansión de variables retrasadas. No es tan a prueba de balas como la solución de dbenham, pero funciona.


Sigo el consejo de KH1 anterior: "Tendrá que cargar toda la ruta y los nombres del archivo junto con DateModified en una matriz, ordenar la matriz, y luego recorrer el conjunto y generar la ruta y el nombre del archivo", pero en un Archivo por lotes. El siguiente programa usa como índice de la matriz la marca de tiempo modificada YYYYMMDDHHMM del archivo. De esta manera, la matriz se mantiene automáticamente ordenada por el comando Batch SET. Los parámetros son los mismos que los del programa dbenham anterior: FileCount y RootFolder opcional.

@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