Как обнаружить (и удалить) файл, если он пуст, с помощью пакетного файла Windows? - PullRequest
12 голосов
/ 21 февраля 2012

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

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

Ответы [ 5 ]

28 голосов
/ 21 февраля 2012

Ссылка, на которую вы ссылались, использовалась для удаления всех файлов 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

EDIT

Я подумал о еще одном способе. Строка поиска FINDSTR "^" будет соответствовать всем строкам файла. Но пустой файл не имеет строк. Поэтому просто удалите файл, если FINDSTR не соответствует строке.

>nul findstr "^" "yourFileName" || del "yourFileName"
5 голосов
/ 21 апреля 2015

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

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

@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 здесь будут удалены только пустые папки.Папки с файлами внутри остаются без изменений.

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

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

@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 (Упорядоченный размер).Параметр / AD не выводит список каталогов, поэтому остаются только истинные файлы (каталоги также указаны как размер 0, поэтому я добавил это).Для каждого файла проверяется размер.Как только найден файл размером более 0 байт, цикл завершается с помощью GOTO: break.Так как файлы отсортированы по размеру, сначала наименьший, его можно безопасно выполнять следующим образом.Огромная экономия времени!

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

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

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

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

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

5 голосов
/ 05 августа 2013

Команда forfiles может быть лучше, например:

echo

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

delete

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

Делайте что хотите

1 голос
/ 05 августа 2013

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

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

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

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

1 голос
/ 21 февраля 2012

Обычно я создаю файл 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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...