it-swarm.com.ru

Как обнаружить (и удалить) файл, если он пуст, с помощью пакетного файла Windows?

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

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

10
Xonatron

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

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

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

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

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

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

Я надеюсь тебе понравится!

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

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

4
Axel Mertes

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

эхо 

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

удалять

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

Делай что хочешь

4
joel Xu

Обычно я создаю файл 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
0
David Welker

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

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

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

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

0
Ashish