Windows batch: delete all empty files in a specified folder

I need to clean my call recordings of empty files from time to time. I used to do it manually, but that’s not what computers are for – right? So let’s automate it.

We’re going to use Windows Task Scheduler and a small batch, to be run once a day.

Let’s start with the batch.

First, we’ll be processing all the files in a specified folder – to get a simple list of files, we’ll use
dir /B

Then, for every file in the list, we’ll be doing some action. We’ll use for loop. By putting the dir command in signle quotes, we tell the loop to run the command and then treat the output of it as a list of files.
for /F %I in ('dir /B') do echo %I

Now, we hit the first problem – %I contains only the first part of each file name – up to a space. It’s because the default delimiter for “for /F” loop includes space. We need to overwrite it. We’ll also take the %I into double quotations
for /F "delims=" "%I" in ('dir /B') do echo "%I"

OK, let’s take care of the action part. We need to check the file size and delete it if it’s zero. Luckily, “for /F” loop can give us the file size of every file processed, with ~z syntax.
for /F "delims=" "%I" in ('dir /B') do if %~zI EQU 0 del "%I"

Unfortunately, directories also report size of 0, so we need to make sure we’re not deleting any directories by the way – let’s differentiate them by the ending with “\”.

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

And finally, we put it into a batch file. We need two things:

  1. To tell it in what folder to look the files for
  2. To change “%” to “%%” – that’s the loop’s requirement

Here’s our final version:
cd C:\Users\Jakub\Desktop\test
for /F "delims=" %%I in ('dir /B') do if not exist "%%I\" if %%~zI EQU 0 del "%%I"

Sharing is caring!

8 comments

  1. James says:

    Hey Jakub,

    Thanks very much for this, it was a massive help!

  2. EranS says:

    You can use the ‘dir /A-D’ in order to not show directories in the search and so you get something simple as that:

    for /F “delims=” %i in (‘dir /B /A-D’) do if %~zi equ 0 del %i

  3. Damian says:

    Thanks for that Jakub, it worked a treat.

  4. Dave says:

    No need to use FOR /F. It is much simpler and more efficient to use the simple FOR.

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

  5. Axel Mertes says:

    Hi All!

    I’ve managed to make a macro that can actually delete all empty files and then all empty folders within a folder hierarchy.

    I took me a while to fiddle it out, but now it works:

    @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”

    It first disables echoing (remove @ECHO OFF if you want to read what actually happens).
    Then it stores the current folder in topLevel variable.
    Next is to walk trough all folders “%D” using the FOR command in the current folder and all sub folders.
    It changes local directory to each of the sub folders found (CD %%D).
    Within each sub folder it deletes all files %%F for which the filesize (~z for %%~zF) is 0.
    When this loop is done all empty files are effectively killed from the disk.
    Now a new FOR command is exectuted to perform a RD %%D to remove every directory.
    Due to DOS being safe here it will delete only EMPTY folders. Folders with files inside keep intact.

    Best regards,
    Axel Mertes

    PS: The biggest nightmare in DOS scripting is understanding when you need %% or %, ‘ or ” etc.

  6. Axel Mertes says:

    Hi All!

    I’ve revamped the script once more, now heavily optimized for speedy processing:

    @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

    The problem with the old one was that the two nested FOR loops touched every single file. As empty files are rare, there is absolutely no need to touch every file and its a big waste of time. I’ve tried to run it on a 25 TByte volume with ~5 million files….

    So I modified the inner loop to sort files by size in a DIR command using the /OS (Ordered Size) option. The /A-D does not list directories, so only true files remain (directories are listed as size 0 too, this is why I added this). For every file the size is checked. Once a file larger than 0 bytes is found, the loop is exited using the GOTO :break. As the files are sorted by size, smallest first, its safe to proceed like this.

    As DOS FOR command has no elegant way to leave the loop I used this strange construct to call the inner loop using goto.

    It seems to run about a few thousand times faster on my large volumes than the previous one ;-)

    Regards
    Axel

  7. Axel Mertes says:

    @Axel Mertes

    Better use this version, as it handles files/folders with spaces in names correctly:

    @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

  8. Joe Huang says:

    I have a batch procedure that I want to exit if the output file named NEWTH.TMP is empty.
    I’ve tried the following but it doesn’t work:
    if %NEWTH.TMP% equ 0 goto :End

    Can anyone tell me what is wrong?

Leave a Reply

Your email address will not be published. Required fields are marked *