Как определить (и удалить) файл, если он пуст, используя пакетный файл Windows?

Как определить, пустой ли файл с использованием командного файла Windows? Я хочу удалить журналы ошибок, если они пусты.

Я знаю, что для решений loop, таких как http://anderwald.info/scripting/windows-batch-delete-all-empty-files-in-a-specified-folder/, но мне было интересно, было ли более элегантное решение, если вы знаете конкретные отдельный файл, который должен быть протестирован, так как я не хочу удалять другие файлы с нулевым байтом в папке.

Ответ 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"

Вы хотите удалить определенный файл, если он равен нулю. Поэтому просто замените свое имя файла для * wild card.

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"

Ответ 2

Команда forfiles может быть приятнее, например:

эхо

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

удалить

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

Сделайте то, что хотите

Ответ 3

Мне удалось создать макрос, который на самом деле может удалять пустые файлы и пустые папки в иерархии папок.

Я взял время, чтобы поиграть, но теперь он работает:

@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. Далее следует пройти через все папки "% D" с помощью команды FOR в текущей папке и всех подпапках. Он изменяет локальный каталог на каждую найденную подпапку (CD %% D). Внутри каждой подпапки с использованием другого цикла FOR находит и удаляет все файлы %% F, для которых размер файла (~ z для %% ~ zF) равен 0. Когда весь этот двойной цикл выполняется, все пустые файлы эффективно уничтожаются с диска. Теперь вызывается новая команда FOR для выполнения RD %% D для удаления всех каталогов. Из-за того, что DOS безопасен, он удаляет только папки EMPTY. Папки с файлами внутри остаются неповрежденными.

Но эй, кто говорит, что не можешь улучшить еще раз?

Я обновил script еще раз, теперь сильно оптимизирован для быстрой обработки:

@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-битном томе с ~ 5 миллионами файлов.

Итак, я изменил внутренний цикл, чтобы сортировать файлы по размеру в команде DIR, используя параметр /OS (Ordered Size). Параметр /A -D не отображает каталоги, поэтому остаются только истинные файлы (каталоги также перечислены как размер 0, поэтому я добавил это). Для каждого файла размер проверяется. После того, как найден файл размером более 0 байтов, цикл завершается с помощью GOTO: break. Поскольку файлы сортируются по размеру, наименьшим первым, безопасно действовать следующим образом. Огромное время!

Поскольку команда DOS FOR не имеет элегантного способа выйти из цикла, я использовал эту странную конструкцию для вызова внутреннего цикла с использованием GOTO: break.

Кажется, он работает в в несколько тысяч раз быстрее на моем большом объеме, чем предыдущий, -)

Надеюсь, вам понравится!

С уважением, Аксель Мертес

PS: Самый большой кошмар в сценариях DOS - это понимание, когда вам нужно %% или%, 'или' и т.д.

Ответ 4

Я обычно создавал бы файл vbscript с файловым файлом FileSystemObject, который обрабатывал бы обнаружение и удаление файла и запускал его из пакетного файла.

Файл 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

simple - найти количество строк в файле, используя

   findstr /R /N "^" file.txt | find /C ":"

теперь, если его счет равен нулю, тогда удалите с использованием условий if.

вы можете использовать цикл через файлы и проверять все файлы в папках