我需要创建一个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
唯一的问题是不要向我展示绝对路径......
编辑:哦,当然我已经尝试过了:
Dir / B / S / TC / O-D
但是/ B参数意味着我之前说过的命令差异很大......
我的意思是:
Dir / S / TC / O-D
命令组(一起)所有子目录中的所有文件,并按日期对它们进行排序。 (GOOD!)
Dir / B / S / TC / O-D
命令按文件夹处理文件夹并对每个文件进行排序并显示。 (BAD!)
所以,如果我需要排序neswest只有100个文件,如果我使用带有“/ B”参数的Batch dir命令,我得到这个:
输出:
(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 ...
所以请不要告诉我关于使用带/ B参数的dir,我知道它很好:(。
再次感谢
答案 0 :(得分: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 "n+=1, 1/(%1-n)" 2>nul || goto finish
)
:finish
del "%tempFile%*"
新的更快版本
我的原始代码为每个目录重新调用WMIC。 WMIC每次调用初始化需要大量时间。通过构建命令脚本并仅调用一次WMIC,我将执行时间减少了45%。性能增益量是树中目录数量的函数。目录数越多,这个新版本就越有帮助。我确信通过转换到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%"
答案 1 :(得分:2)
我遵循上面KH1的建议:“你需要将所有文件路径和名称与DateModified一起加载到一个数组中,对数组进行排序,然后遍历数组并输出文件路径和名称”,但是在批处理文件中。下面的程序使用该文件的YYYYMMDDHHMM修改时间戳作为数组的索引。这样,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
答案 2 :(得分: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
主要思想是使用Disconnected ADO Recordset来存储和排序文件夹树中的文件集合。
答案 3 :(得分:1)
您可以使用for
命令和〜语法(请参阅for /?
)来执行此操作:
(for /r %A in (*) do @echo %~tA %A ) | sort /r
括号的使用允许单个重定向整个for
到sort
。没有括号,每个echo
都会被重定向到单个sort
,因此不会进行排序。
@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 /?
)和延迟变量扩展,将日期转换为yyyy-mm-dd格式。它不像dbenham的解决方案那样具有防弹功能,但它确实有效。