【问题标题】:How do I Detect (and Delete) a File if it is Empty using a Windows Batch File?如果文件为空,如何使用 Windows 批处理文件检测(并删除)文件?
【发布时间】:2012-02-21 14:09:19
【问题描述】:

如何使用 Windows 批处理文件检测文件是否为空?如果错误日志为空,我想删除它们。

我知道 for 循环解决方案,例如 https://web.archive.org/web/20171110203759/http://anderwald.info/scripting/windows-batch-delete-all-empty-files-in-a-specified-folder/,但我想知道如果您知道需要测试的特定单个文件是否有更优雅的解决方案,因为我可能不希望删除其他零文件夹中的字节文件。

【问题讨论】:

    标签: windows batch-file cmd


    【解决方案1】:

    您引用的链接使用以下内容删除所有长度为0的文件

    for /F "delims=" "%I" in ('dir /B') do if not exist "%I\" if %~zI EQU 0 del "%I"
    

    这更复杂,效率也不高。使用起来要简单得多:

    for %F in (*) do if %~zF equ 0 del "%F"
    

    如果特定文件的长度为零,您想删除它。因此,只需将您的文件名替换为 * 通配符即可。

    for %F in ("yourFileName") do if %~zF equ 0 del "%F"
    

    如果您要在批处理文件中使用它,则需要将所有百分比加倍(%%F%%~zF

    如果您不想使用 FOR 循环,则可以使用 CALL 参数 - 它使用与 FOR 变量相同的修饰符。但是, CALL 比 FOR 慢(在您的情况下可能并不重要)

    @echo off
    call :deleteIfEmpty "yourFileName"
    exit /b
    
    :deleteIfEmpty
    if %~z1 eq 0 del %1
    exit /b
    

    编辑

    我想到了另一种方法。 "^" 的 FINDSTR 搜索字符串将匹配文件的所有行。但是一个空文件没有任何行。因此,如果 FINDSTR 无法匹配一行,只需删除该文件即可。

    >nul findstr "^" "yourFileName" || del "yourFileName"
    

    【讨论】:

    • 嗯...所以我也想到了这一点,只对我的文件使用了一个 for 循环。我希望有比这更优雅的东西,但这样就可以了。
    • @MatthewDoucette 我添加了一个使用 CALL 而不是 FOR 的替代方法
    • @MatthewDoucette - 我添加了另一种使用 FINDSTR 的方法。我还修复了 CALL 解决方案中的一个愚蠢错误(标签中的冒号太多)。
    • 很高兴看到这个问题不仅得到了回答,而且得到了解释和概括!
    • 对于递归文件搜索,请执行for /r %F。要禁止输出,请在 if 命令之前使用 @ 符号 - @if。相关问题:stackoverflow.com/questions/18014662/…stackoverflow.com/questions/4176962/…
    【解决方案2】:

    我设法制作了一个宏,它实际上可以删除文件夹层次结构中的空文件和空文件夹

    我花了一段时间才弄明白,但现在可以了:

    @ECHO OFF
    SET topLevel=%cd%
    FOR /D /R %%D IN (*) DO ( 
      CD %%D
      FOR %%F IN (*) DO IF %%~zF EQU 0 DEL "%%F"
    )
    CD %topLevel%
    FOR /F "usebackq delims=" %%D IN (`"DIR/AD/B/S|SORT/R"`) DO RD "%%D"
    

    它首先禁用回显(如果您想了解实际发生的情况,请删除 @ECHO OFF)。 然后它将当前文件夹存储在 topLevel 变量中。 接下来是在当前文件夹和所有子文件夹中使用 FOR 命令遍历所有文件夹“%D”。 它将本地目录更改为找到的每个子文件夹 (CD %%D)。 在使用另一个 FOR 循环的每个子文件夹中,它会查找并删除所有文件大小为 %%F 的文件(对于 %%~zF 的 ~z)为 0。 当整个双循环完成后,所有空文件都被有效地从磁盘中杀死。 现在执行一个新的 FOR 命令来执行 RD %%D 以删除每个目录。 由于 DOS 在这里是安全的,它只会删除 EMPTY 文件夹。包含文件的文件夹保持不变。

    但是,谁说你不能再提高一次?

    我再次修改了脚本,现在高度优化以实现快速处理

    @ECHO OFF
    SET topLevel=%CD%
    FOR /D /R %%D IN (*) DO (
      CD %%D 
      CALL :innerLoop
    )
    CD %topLevel%
    FOR /F "usebackq delims=" %%D IN (`"DIR /AD/B/S | SORT /R"`) DO RD "%%D"
    GOTO :break
    
    :innerLoop
      FOR /F "delims=" %%F IN ('DIR/B/A-D/OS') DO IF %%~zF EQU 0 (DEL "%%F") ELSE (GOTO :break)
    
    :break
    

    前一个的问题是两个嵌套的 FOR 循环触及了每个文件。由于空文件很少见,因此绝对没有必要触摸每个文件,这非常浪费时间。我尝试在 25 TByte 的卷上运行它,其中包含大约 500 万个文件。

    所以我修改了内部循环,使用 /OS(Ordered Size)选项在 DIR 命令中按大小对文件进行排序。 /A-D 选项不列出目录,所以只保留真正的文件(目录也被列为大小 0,这就是我添加它的原因)。对于每个文件,都会检查大小。一旦找到大于 0 字节的文件,就使用 GOTO :break 退出循环。由于文件按大小排序,最小的在前,这样可以安全地进行。更安全!

    由于 DOS FOR 命令没有优雅的方式离开循环,我使用这个奇怪的结构来调用内部循环,使用 GOTO :break。

    在我的大音量上,它的运行速度似乎比上一个快几千倍 ;-)

    希望你喜欢!

    最好的问候, 阿克塞尔·默特斯

    PS:DOS 脚本中最大的噩梦是理解何时需要 %% 或 %、' 或 " 等。

    【讨论】:

    • 您的优化版本做得很好,但是,它不是问题的答案。 OP 明确询问如何测试和删除单个特定文件,而不是整个层次结构。另外,您开发的是批处理脚本,而不是宏。
    【解决方案3】:

    forfiles 命令可能会更好,像这样:

    回声

    forfiles /c "cmd /c if @fsize==0  echo @file"
    

    删除

    forfiles /c "cmd /c if @fsize==0  del @file"
    

    做你想做的事

    【讨论】:

    • FORFILES 并非普遍适用于所有版本的 Windows。它也很 S L O W 。 . . .
    • @dbenham 确实如此,但您在此解决方案中有一个很大的优势:您可以指定所需的文件大小。您还可以找到 4 或 5 字节大小的“空”/无用文件(仅包括 CR 或 CR/LF 或除 UTF-8-BOM 之外的其他控制字符)。我知道 1 或 2 个字节也可以包含 A 或 ZZ,但这对于日志文件也是无用的。-)
    • 如何指定文件夹路径?
    【解决方案4】:

    我通常会使用 FileSystemObject 创建一个 vbscript 文件来处理文件的检测和删除,然后从批处理文件中运行它。

    VBScript 文件:

    Dim oFSO
    Dim oFile
    Dim ts
    strFilePath = "<insert path to file here>"
    Set oFSO = CreateObject("Scripting.FileSystemObject")
    if oFSO.FileExists(strFilePath) then
       Set oFile = oFSO.GetFile(strFilePath)
       strLine = ""
       linecount = 0
       blnShouldDelete = True
       Set ts = oFile.OpenAsTextStream(1, -2)
       Do While ts.AtEndOfStream <> True
          linecount = linecount + 1
          strLine = ts.ReadLine
    
          if Len(strLine) > 0 then
             blnShouldDelete = False
          end if 
       Loop
       ts.Close
    
       if (linecount = 0 Or linecount = 1) And blnShouldDelete = True then
           oFile.Delete
       end if
    end if
    set oFSO = Nothing
    

    对于批处理文件:

    cscript <filename>.vbs  
    PAUSE
    

    【讨论】:

      【解决方案5】:

      简单就是使用

      来查找文件中的行数
         findstr /R /N "^" file.txt | find /C ":"
      

      现在如果它的计数为零,则使用 if 条件删除。

      您可以使用循环遍历文件并检查文件夹中的所有文件

      【讨论】:

        猜你喜欢
        • 2017-09-10
        • 1970-01-01
        • 1970-01-01
        • 2011-02-01
        • 2018-02-24
        • 1970-01-01
        • 1970-01-01
        • 2013-02-25
        • 1970-01-01
        相关资源
        最近更新 更多