【问题标题】:Find out if file is older than 4 hours in Batch file在批处理文件中找出文件是否超过 4 小时
【发布时间】:2011-08-03 14:58:42
【问题描述】:

很简单,我如何确定文件夹中的特定文件是否超过 X 小时? 文件名和位置始终相同。

谢谢

【问题讨论】:

    标签: windows batch-file cmd


    【解决方案1】:

    在将文件时间与批处理代码进行比较时,必须考虑以下内容:

    1. 日期和时间格式设置
    2. 存储介质的文件系统
    3. 时区、夏令时
    4. 自动调整夏令时
    5. Windows 版本

    1. 日期和时间格式设置

    DATETIME 环境变量 在访问时(而不是在批处理开始时)返回 current 日期和时间,格式取决于Windows Region and Language settings。国家/地区定义日期和时间格式。

    甚至可以用DD.MM.YYYY(带前导零的日期和月份)和HH:mm:ss(带前导零的小时、分钟和秒的24小时格式)定义德国短日期格式.但这并不意味着 DATETIME 的值真的使用这种格式。例如,TIME 的格式为H:mm:ss,ms,即使定义了HH:mm:ss,也意味着选择了德国国家/地区,这意味着小时没有前导零,但在分钟和秒,以及逗号后的毫秒时间细绳。日期字符串也可以有或没有工作日,具体取决于区域设置。

    还有%~t 模式可以获取目录或文件的最后修改日期和时间。在命令提示符窗口call /?for /? 中运行,并阅读为这两个命令显示的所有帮助页面以了解详细信息。 %~t 返回的日期和时间字符串的格式以及在命令 DIR 的输出中显示的格式也取决于 Windows 区域设置,但通常不等于变量 DATE 和 时间。文件或目录的最后修改时间通常返回日期/时间字符串中没有第二个值。

    最好使用以下批处理文件找出最好在上午 10:00 之前执行的当前用户当前计算机上的格式。

    @echo off
    echo Current date/time: %DATE% %TIME%
    for %%I in ("%~f0") do echo Batch file time:   %%~tI
    pause
    

    1. 存储介质的文件系统

    在 Windows 文件系统上,file times 使用两种存储格式:

    • 在使用 NTFS 的存储介质上,使用了 NTFS precision time,它是自凌晨 12:00 以来经过的 100 纳秒间隔的 64 位数字。 1601 年 1 月 1 日协调世界时 (UTC)。

    • 在使用 FAT、FAT16、FAT32 或 exFAT 的存储介质上,文件时间以 DOS Date Time 格式存储,具有两个分辨率为 2 秒的 16 位值并使用当前本地时间。

    这意味着 FAT 介质上的文件不可能出现奇数秒,但 NTFS 介质上的文件不可能出现奇数秒。将 NTFS 驱动器上最后修改时间奇数秒的文件复制到 FAT32 驱动器会导致相同文件的最后修改时间相差 1 秒。

    NTFS 媒体上的文件时间以 UTC 格式存储。因此,%~t 或命令 DIR 返回的内容以及在 Windows 资源管理器中显示的内容取决于

    • 当前时区,
    • 这个时区的夏令时,
    • 如果当前时间在夏令时范围内,
    • 如果当前启用了夏令时自动调整。

    更改这 4 个参数中的任何一个都会立即更改 NTFS 存储介质上文件和目录的所有显示文件时间。

    FAT 介质上的文件时间与创建、修改或上次访问时使用的本地时间一样或多或少是恒定的,但请进一步阅读以了解详细信息。


    1. 时区、夏令时

    由于 NTFS 媒体上的文件时间以 UTC 存储,但以本地时间显示,因此当前时区和该时区的夏令时对于文件时间比较很重要,尤其是在对 NTFS 和 FAT32 驱动器上的文件进行比较时.

    但对于 FAT 媒体上的文件,时区和夏令时设置可能很重要,具体取决于 Windows 版本。阅读下文了解详情。


    1. 自动调整夏令时

    有自动调整夏令时的设置,在默认启用时变得很重要,并且当前设置的时区定义了夏令时调整。

    例如,夏令时目前在欧洲有效。在 Windows 的时钟设置中禁用此选项会导致 NTFS 媒体上显示的文件时间立即更改 -1 小时,并且还会导致 FAT 媒体上的许多文件取决于 Windows 版本。

    在比较 NTFS 和 FAT 介质上的文件时间时,必须考虑到由夏令时调整引起的 1 小时时差。


    1. Windows 版本

    所有 Windows NT 版本都支持 NTFS。在支持 NTFS 的所有 Windows 版本上,文件和目录的文件时间行为是相同的。

    但如何解释 FAT 介质上的文件时间取决于 Windows 版本。以前的 Windows Vista FAT 媒体上的文件时间独立于时区的更改、夏令时设置和夏令时的自动调整。在 Windows 2000 和 Windows XP 上,文件的最后修改日期/时间是恒定的。

    但在 Windows Vista 及更高版本上,FAT 媒体上显示的文件时间取决于夏令时和夏令时的自动调整。时区没有直接关系。选择当前使用的另一个时区不会像更改 NTFS 介质上的文件那样更改 FAT 介质上文件的显示文件时间。但是如果当前时间在活动时区的夏令时范围内,并且启用了夏令时的自动调整,并且文件或目录的本地时间在夏令时范围内,则Windows Vista会增加+1小时然后。在标准时间内最后一次在 FAT 驱动器上修改的文件在一年中保持不变;仅在 DST 期间最后修改的文件显示有或没有 +1 小时,具体取决于启用自动 DST 调整的当前时间。

    例如,当 Windows 7 机器上的 FAT32 驱动器上的文件夹的公共共享并使用 Windows XP 机器连接到此公共文件夹时,不同的 FAT 文件时间管理可能会非常混乱。上次修改于 2015 年 9 月 19 日 17:39:08 存储在 Windows 7 PC 上的 FAT32 驱动器上的文件今天由 Windows 7 显示,文件时间为 19.09.2015 17:39:08,文件时间为 19.09.2015 17:39:08,但在 2 个月内未在 19.09.2015 16:39:08 修改,Windows XP 今天和未来在连接的 Windows 7 PC 上显示相同的文件,文件时间为 19.09.2015 17:39:08。

    将存档(ZIP、RAR、...)中存储的文件的文件时间与 NTFS 或 FAT 媒体上的文件进行比较真的是一场噩梦。


    1. 比较文件时间和当前时间

    对于这个比较文件的最后修改时间和当前时间的任务,只需考虑日期和时间格式设置就足够了。

    下面的批处理代码使用了我在Batch file to delete files older than N days 上的回答中详细解释的代码。在使用下面的代码之前应该阅读这个解释。

    取决于变量 DATETIME 的日期/时间格式以及 %~tI 为本地 Windows PC 上的文件返回的日期/时间字符串,它可能是需要对代码进行小的修改。在批处理代码的注释行中给出了适当的提示。

    @echo off
    setlocal EnableExtensions DisableDelayedExpansion
    
    rem Get seconds since 1970-01-01 for current date and time.
    rem From date string only the last 10 characters are passed to GetSeconds
    rem which results in passing dd/mm/yyyy or dd.mm.yyyy in expected format
    rem to this subroutine independent on date string of environment variable
    rem DATE is with or without abbreviated weekday at beginning.
    call :GetSeconds "%DATE:~-10% %TIME%"
    
    rem Subtract seconds for 4 hours (4 * 3600 seconds) from seconds value.
    set /A "CompareTime=Seconds-4*3600"
    
    rem Define batch file itself as the file to compare time by default.
    set "FileToCompareTime=%~f0"
    
    rem If batch file is started with a parameter and the parameter
    rem specifies an existing file (or directory), compare with last
    rem modification date of this file.
    if not "%~1" == "" if exist "%~1" set "FileToCompareTime=%~1"
    
    rem Get seconds value for the specified file.
    for %%F in ("%FileToCompareTime%") do call :GetSeconds "%%~tF:0"
    
    rem Compare the two seconds values.
    if %Seconds% LSS %CompareTime% (
        echo File %FileToCompareTime% was last modified for more than 4 hours.
    ) else (
        echo File %FileToCompareTime% was last modified within the last 4 hours.
    )
    endlocal
    goto :EOF
    
    
    rem No validation is made for best performance. So make sure that date
    rem and hour in string is in a format supported by the code below like
    rem MM/DD/YYYY hh:mm:ss or M/D/YYYY h:m:s for English US date/time.
    
    :GetSeconds
    rem If there is " AM" or " PM" in time string because of using 12 hour
    rem time format, remove those 2 strings and in case of " PM" remember
    rem that 12 hours must be added to the hour depending on hour value.
    set "DateTime=%~1"
    set "Add12Hours=0"
    if not "%DateTime: AM=%" == "%DateTime%" (
        set "DateTime=%DateTime: AM=%"
    ) else if not "%DateTime: PM=%" == "%DateTime%" (
        set "DateTime=%DateTime: PM=%"
        set "Add12Hours=1"
    )
    
    rem Get year, month, day, hour, minute and second from first parameter.
    for /F "tokens=1-6 delims=,-./: " %%A in ("%DateTime%") do (
        rem For English US date MM/DD/YYYY or M/D/YYYY
        set "Day=%%B" & set "Month=%%A" & set "Year=%%C"
        rem For German date DD.MM.YYYY or English UK date DD/MM/YYYY
        rem set "Day=%%A" & set "Month=%%B" & set "Year=%%C"
        set "Hour=%%D" & set "Minute=%%E" & set "Second=%%F"
    )
    
    rem Remove leading zeros from the date/time values or calculation could be wrong.
    if "%Month:~0,1%"  == "0" if not "%Month:~1%"  == "" set "Month=%Month:~1%"
    if "%Day:~0,1%"    == "0" if not "%Day:~1%"    == "" set "Day=%Day:~1%"
    if "%Hour:~0,1%"   == "0" if not "%Hour:~1%"   == "" set "Hour=%Hour:~1%"
    if "%Minute:~0,1%" == "0" if not "%Minute:~1%" == "" set "Minute=%Minute:~1%"
    if "%Second:~0,1%" == "0" if not "%Second:~1%" == "" set "Second=%Second:~1%"
    
    rem Add 12 hours for time range 01:00:00 PM to 11:59:59 PM,
    rem but keep the hour as is for 12:00:00 PM to 12:59:59 PM.
    if %Add12Hours% == 1 if %Hour% LSS 12 set /A Hour+=12
    
    set "DateTime="
    set "Add12Hours="
    
    rem Must use two arrays as more than 31 tokens are not supported
    rem by command line interpreter cmd.exe respectively command FOR.
    set /A "Index1=Year-1979"
    set /A "Index2=Index1-30"
    
    if %Index1% LEQ 30 (
        rem Get number of days to year for the years 1980 to 2009.
        for /F "tokens=%Index1% delims= " %%Y in ("3652 4018 4383 4748 5113 5479 5844 6209 6574 6940 7305 7670 8035 8401 8766 9131 9496 9862 10227 10592 10957 11323 11688 12053 12418 12784 13149 13514 13879 14245") do set "Days=%%Y"
        for /F "tokens=%Index1% delims= " %%L in ("Y N N N Y N N N Y N N N Y N N N Y N N N Y N N N Y N N N Y N") do set "LeapYear=%%L"
    ) else (
        rem Get number of days to year for the years 2010 to 2038.
        for /F "tokens=%Index2% delims= " %%Y in ("14610 14975 15340 15706 16071 16436 16801 17167 17532 17897 18262 18628 18993 19358 19723 20089 20454 20819 21184 21550 21915 22280 22645 23011 23376 23741 24106 24472 24837") do set "Days=%%Y"
        for /F "tokens=%Index2% delims= " %%L in ("N N Y N N N Y N N N Y N N N Y N N N Y N N N Y N N N Y N N") do set "LeapYear=%%L"
    )
    
    rem Add the days to month in year.
    if "%LeapYear%" == "N" (
        for /F "tokens=%Month% delims= " %%M in ("0 31 59 90 120 151 181 212 243 273 304 334") do set /A "Days+=%%M"
    ) else (
        for /F "tokens=%Month% delims= " %%M in ("0 31 60 91 121 152 182 213 244 274 305 335") do set /A "Days+=%%M"
    )
    
    rem Add the complete days in month of year.
    set /A "Days+=Day-1"
    
    rem Calculate the seconds which is easy now.
    set /A "Seconds=Days*86400+Hour*3600+Minute*60+Second"
    
    rem Exit this subroutine.
    goto :EOF
    

    rojo 添加了有关如何使用wmic(Windows Management Instrumentation 命令行实用程序)忽略日期和时间格式设置、文件系统和 Windows 版本的信息。

    使用 wmic 的优点是日期/时间字符串的格式固定,因此批处理代码适用于所有 Windows 计算机,而无需适应本地日期/时间格式。

    由于GetFileTime 函数的内部使用(很可能),使用 wmic 的 Windows 版本也无关紧要。

    文件系统仅在评估本地时间/文件时间与 UTC 的分钟偏移量时才变得重要。命令 wmic 在 FAT 驱动器上仅返回 +*** 以表示与 UTC 的分钟偏移量,而分钟偏移量对于 NTFS 驱动器上文件的最后修改文件时间是正确的。

    NTFS 和 FAT32 驱动器上相同文件的示例:

    NTFS:  20071011192622.000000+120
    FAT32: 20071011192622.000000+***
    

    +120 是 CET(中欧时间)+60 分钟和有效夏令时 +60 分钟的总和,即 CEST(中欧夏令时)+120 分钟。

    因此,下面的批处理代码不会评估与 UTC 的分钟偏移量,这在将文件的最后修改文件时间与当前本地时间进行比较时不需要。

    此外,必须在 wmic 命令行中始终使用完整路径指定文件名。仅指定当前目录中文件的文件名或具有相对路径的文件名是行不通的。并且每个反斜杠必须在带有路径的文件名中再用一个反斜杠进行转义。

    使用 wmic 的主要缺点是速度。根据Process Monitor 日志(几次运行的平均值),上面的批处理代码在我的计算机上需要大约 50 毫秒才能完成。下面调用 wmic 两次的批处理代码需要大约 1500 毫秒才能完成相同的任务(也是平均值)。因此,在大量文件上使用 wmic 绝对不是一个好主意,如果可以避免,因为本地日期/时间格式是已知的。

    @echo off
    setlocal EnableExtensions DisableDelayedExpansion
    
    rem Get seconds since 1970-01-01 for current date and time.
    for /F "tokens=2 delims==." %%T in ('%SystemRoot%\System32\wbem\wmic.exe OS GET LocalDateTime /VALUE') do call :GetSeconds %%T
    
    rem Subtract seconds for 4 hours (4 * 3600 seconds) from seconds value.
    set /A "CompareTime=Seconds-4*3600"
    
    rem Define batch file itself as the file to compare time by default.
    set "FileToCompareTime=%~f0"
    
    rem If batch file is started with a parameter and the parameter
    rem specifies an existing file (or directory), compare with last
    rem modification date of this file.
    if not "%~1" == "" if exist "%~f1" set "FileToCompareTime=%~f1"
    
    rem Get seconds value for the specified file.
    set "DataFile=%FileToCompareTime:\=\\%"
    for /F "usebackq tokens=2 delims==." %%T in (`%SystemRoot%\System32\wbem\wmic.exe DATAFILE where "name='%DataFile%'" GET LastModified /VALUE`) do call :GetSeconds %%T
    
    rem Compare the two seconds values.
    if %Seconds% LSS %CompareTime% (
        echo File %FileToCompareTime% was last modified for more than 4 hours.
    ) else (
        echo File %FileToCompareTime% was last modified within the last 4 hours.
    )
    endlocal
    goto :EOF
    
    
    rem Date/time format used by the command line utility of Windows
    rem Management Instrumentation is always YYYYMMDDHHmmss with a
    rem dot and a 6 digit microsecond value and plus/minus 3 digit
    rem time offset to UTC in minutes independent on region and
    rem language settings. Microsecond is always 000000 for a file
    rem time. The minutes offset including time zone offset and
    rem current daylight saving time offset is returned for a file
    rem time only for a file on an NTFS drive. Minutes offset is
    rem +*** for a file on a FAT drive (at least on Windows XP).
    
    :GetSeconds
    rem Get year, month, day, hour, minute and second from first parameter.
    set "DateTime=%~1"
    set "Year=%DateTime:~0,4%"
    set "Month=%DateTime:~4,2%"
    set "Day=%DateTime:~6,2%"
    set "Hour=%DateTime:~8,2%"
    set "Minute=%DateTime:~10,2%"
    set "Second=%DateTime:~12,2%"
    rem echo Date/time is: %Year%-%Month%-%Day% %Hour%:%Minute%:%Second%
    
    rem Remove leading zeros from the date/time values or calculation could be wrong.
    if %Month:~0,1%  == 0 set "Month=%Month:~1%"
    if %Day:~0,1%    == 0 set "Day=%Day:~1%"
    if %Hour:~0,1%   == 0 set "Hour=%Hour:~1%"
    if %Minute:~0,1% == 0 set "Minute=%Minute:~1%"
    if %Second:~0,1% == 0 set "Second=%Second:~1%"
    
    rem Must use two arrays as more than 31 tokens are not supported
    rem by command line interpreter cmd.exe respectively command FOR.
    set /A "Index1=Year-1979"
    set /A "Index2=Index1-30"
    
    if %Index1% LEQ 30 (
        rem Get number of days to year for the years 1980 to 2009.
        for /F "tokens=%Index1% delims= " %%Y in ("3652 4018 4383 4748 5113 5479 5844 6209 6574 6940 7305 7670 8035 8401 8766 9131 9496 9862 10227 10592 10957 11323 11688 12053 12418 12784 13149 13514 13879 14245") do set "Days=%%Y"
        for /F "tokens=%Index1% delims= " %%L in ("Y N N N Y N N N Y N N N Y N N N Y N N N Y N N N Y N N N Y N") do set "LeapYear=%%L"
    ) else (
        rem Get number of days to year for the years 2010 to 2038.
        for /F "tokens=%Index2% delims= " %%Y in ("14610 14975 15340 15706 16071 16436 16801 17167 17532 17897 18262 18628 18993 19358 19723 20089 20454 20819 21184 21550 21915 22280 22645 23011 23376 23741 24106 24472 24837") do set "Days=%%Y"
        for /F "tokens=%Index2% delims= " %%L in ("N N Y N N N Y N N N Y N N N Y N N N Y N N N Y N N N Y N N") do set "LeapYear=%%L"
    )
    
    rem Add the days to month in year.
    if "%LeapYear%" == "N" (
        for /F "tokens=%Month% delims= " %%M in ("0 31 59 90 120 151 181 212 243 273 304 334") do set /A "Days+=%%M"
    ) else (
        for /F "tokens=%Month% delims= " %%M in ("0 31 60 91 121 152 182 213 244 274 305 335") do set /A "Days+=%%M"
    )
    
    rem Add the complete days in month of year.
    set /A "Days+=Day-1"
    
    rem Calculate the seconds which is easy now.
    set /A "Seconds=Days*86400+Hour*3600+Minute*60+Second"
    
    rem Exit this subroutine.
    goto :EOF
    

    【讨论】:

    • 你从我这里得到 +1,因为这是一篇令人印象深刻的文章和解释。不过,只是一个简短的说明。第 1、2 和 5 号可以通过使用与区域设置和文件系统无关的 WMI 查询来否定。 wmic os get localdatetime 当前日期和时间;和 wmic datafile where "name='c:\\path\\to\\file.ext'" get lastmodified 以相同格式表示上次修改时间。两个结果都以 GMT 为单位,并在值的末尾报告时区/DST 偏移量。
    • 感谢@rojo 提供这些额外信息。我添加了一个使用 wmic 的代码示例,其中包含有关使用 wmic 的优缺点的一些信息。
    • 我还必须说你的回答让我印象深刻。出于这个原因,我不得不再次打开赏金,但这次是为你。即使事实证明赏金以 2 的倍数递增,这也是值得的。
    • 非常感谢@Paul。我想,在阅读了 StackOverflow 上的许多“早于”问题后,我认为是时候写下我所知道的关于 Windows 文件时间管理和文件时间比较的所有内容了。我希望这个大答案可以帮助许多其他人。欢迎随时提供有关文件时间的其他意见。
    • 不幸的是,wmic 方法还有另一个问题:您不能指定同时包含 ,) 的文件路径——另请参阅我的问题:How to escape both comma and closing parenthesis in WHERE clause of WMIC?
    【解决方案2】:

    或者,您可以使用 C# 创建一个简单的程序,例如:

    // compile using c:\Windows\Microsoft.NET\Framework\v3.5\csc FileByAge.cs
    using System;
    using System.IO;
    
    public static class Program
    {
      public static void Main(string[] args)
      {
        double age = double.Parse(args[0]);
        string fileName;
        while ((fileName = Console.ReadLine()) != null)
        {
          if(age >= (DateTime.Now - new FileInfo(fileName).CreationTime).TotalHours)
          {
            continue;
          }
          Console.WriteLine(fileName);    
        }
      }
    }
    

    然后可以使用该程序在批处理文件中查找所有超过 2 小时的文件:

    for /F "delims=" %f in ('dir /B *.txt^|FileByAge.exe 2') do echo %f
    

    改进的自编译版本

    正如@Paul 所提到的,甚至可以构建一个 hacky 混合批处理/c# 文件,该文件将自行编译和运行:

    @echo off
    setlocal
    set CsFile=%TEMP%\%~n0.cs
    set ExeFile=%TEMP%\%~n0.exe
    pushd %SystemRoot%\Microsoft.NET\Framework
    for /F %%f in ('dir /B /O:-N v*') do cd %%f & goto :BreakLoop;  
    :BreakLoop
    (echo /* & type "%~f0") > "%CsFile%"
    csc.exe /nologo /out:"%ExeFile%" "%CsFile%" 
    del "%CsFile%"
    popd
    more | "%ExeFile%" %*
    del "%ExeFile%"
    endlocal
    goto:eof
    */
    
    using System;
    using System.IO;
    
    public static class Program
    {
        public static void Main(string[] args)
        {
            var olderThen = args[0].Contains("older");
            var targetAge = double.Parse(args[1]);
            string fileName;
            while ((fileName = Console.ReadLine()) != null)
            {
                if (string.Empty == fileName)
                {
                    continue;
                }
                var fileAge = (DateTime.Now - new FileInfo(fileName).CreationTime).TotalHours;
                if (olderThen ? targetAge > fileAge : targetAge < fileAge)
                {
                    continue;
                }
                Console.WriteLine(fileName);
            }
        }
    }
    

    并且可以这样使用:

    for /F "delims=" %f in ('dir /B *.txt^|FileByAge.bat older 2') do echo %f
    

    【讨论】:

    • @iKiWiXz 是的,它是一个 C# 程序,您可以在几乎任何 Windows PC 上的批处理文件中编译和使用它。如果您愿意,您甚至可以将所有内容集成到批处理文件中。对一个可能对 OP 没有帮助但有效并且可能对其他人有帮助的有效解决方案投反对票有点挑剔。
    • 嗨@Martin +1 btw。可能脚本可以即时编译源代码。我已经看到了一个混合脚本可以做到这一点。我会看看它。谢谢
    • @Paul 空格问题来自for 命令。只需添加"delims=" 即可修复它。我还按照您的建议添加了脚本的自编译版本。
    • @Paul 我添加了一个参数来指定比较运算符
    • @Paul 是的,只需传递不包含单词older 的内容 - e。 G。 younger
    【解决方案3】:

    对此的解决方案将很大程度上取决于预期的时间范围,因为 AFAIK 在没有外部程序的情况下,您不会在批处理文件中将时间作为一个整数。这意味着您必须在脚本中解析时间值,并且解析量和所需的计算次数取决于您需要它工作的范围。 这是一个简单的解决方案。它假定文件不能超过 24 小时。

    set "filename=myfile.txt"
    rem extract current date and time
    for /f "tokens=1-5 delims=.:, " %%a in ("%date% %time%") do (
      set day=%%a&set mon=%%b&set yr=%%c&set hr=%%d&set min=%%e
    )
    rem extract file date and time
    for /f "tokens=1-5 delims=.:, " %%a in ('"dir %filename%|find "%filename%""') do (
      set fday=%%a&set fmon=%%b&set fyr=%%c&set fhr=%%d&set fmin=%%e
    )
    rem calculate age of file (in minutes)
    set /a "age=((hr*60+min)-(fhr*60+fmin)+(24*60))%%(24*60)"
    set /a "max=4*60"
    if %age% geq %max% echo.file is older than 4 hours
    

    【讨论】:

    • 此答案由两位用户投票赞成。请有人为我解释一下这个批处理代码是如何工作的?在我在 Windows XP 上的测试中,第二个 for 循环不会产生预期的结果,因为 '"dir %filename%|find "%filename%""' 而不是 'dir "%filename%" ^| find "%filename%"'。结果是每个文件都超过 4 小时。即使有了这个更正,批处理代码也只能用于不包含路径的文件名,因为 dir 只输出文件名,但 find 搜索带有路径的文件名。
    • 下一个问题是从指定文件中获取最后修改时间,该文件必须没有路径,因此在当前目录中,来自用 find 过滤的 dir 的输出 b> 并由 for 使用更正的 'dir "%filename%" ^| find "%filename%"' 解析是由于 find 搜索没有参数 /I 区分大小写。因此,如果没有路径的文件名没有在第二行完全按照存储介质上存储的拼写形式指定,find 将始终无法在 dir 的输出中找到文件的行乙>。我也看到了这段代码的其他问题。对不起!
    • @mofi 我从未在 XP 上测试过这个脚本,正如您在自己的回答中解释的那样,这种时间/日期/修改日期解析方法与操作系统版本和语言环境非常紧密地结合在一起。我确实在我的回答中指定这是一个简单的解决方案,但它确实在 2011 年我发布此内容时在 win7 上工作;)
    • @Mofi 有趣的事情:前几天我真的想到了这篇文章,并考虑使用 wmic 而不是 %date%、%time%、dir 和 find 来更新我的答案。但是现在看到你的回答,我想我不会打扰;)很抱歉我的解决方案不适合你。
    【解决方案4】:

    纯批次在日期数学方面很糟糕。如果您的脚本在午夜后不久运行会发生什么?如果时间检查跨越夏令时更改怎么办?

    我建议调用 Windows Script Host 并借鉴一种可以更好地处理日期/时间数学的语言。这是一个混合批处理/JScript 脚本,可以很容易地计算文件或目录的年龄。使用 .bat 扩展名保存它并试一试。

    @if (@CodeSection==@Batch) @then
    
    @echo off
    setlocal
    
    set "file=C:\Path\To\File.ext"
    
    for /f %%I in ('cscript /nologo /e:JScript "%~f0" "%file%"') do (
        rem // value contained in %%I is in minutes.
    
        if %%I gtr 240 (
    
            echo %file% is over 4 hours old.
    
            rem // do stuff here to take whatever actions you wish
            rem // if the file is over 4 hours old.
        )
    )
    
    goto :EOF
    
    @end // end batch portion / begin JScript hybrid chimera
    
    var fso = new ActiveXObject("scripting.filesystemobject"),
        arg = WSH.Arguments(0),
        file = fso.FileExists(arg) ? fso.GetFile(arg) : fso.GetFolder(arg);
    
    // Use either DateCreated, DateLastAccessed, or DateLastModified.
    // See http://msdn.microsoft.com/en-us/library/1ft05taf%28v=vs.84%29.aspx
    // for more info.
    
    var age = new Date() - file.DateLastModified;
    WSH.Echo(Math.floor(age / 1000 / 60));
    

    有关批处理/JScript 混合脚本的更多信息,see this GitHub page。上面使用的样式类似于该页面上的 Hybrid.bat。这个答案是based on another。就其价值而言,PowerShell 还擅长处理日期数学;但 WSH 的执行速度要快得多。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2010-09-08
      • 2011-10-21
      • 2011-03-02
      • 1970-01-01
      • 1970-01-01
      • 2011-11-01
      相关资源
      最近更新 更多