web-dev-qa-db-de.com

Wie erkenne (und lösche) ich eine leere Datei mithilfe einer Windows-Stapeldatei?

Wie erkenne ich anhand einer Windows-Batchdatei, ob eine Datei leer ist? Ich möchte Fehlerprotokolle löschen, wenn sie leer sind.

Ich kenne for-Loop-Lösungen wie http://anderwald.info/scripting/windows-batch-delete-all-empty-files-in-a-specified-folder/ , habe mich aber gefragt, ob es solche gibt Eine elegantere Lösung, wenn Sie die betreffende einzelne Datei kennen, die getestet werden muss, da ich möglicherweise keine anderen Null-Byte-Dateien im Ordner löschen möchte.

10
Xonatron

Der von Ihnen angegebene Link hat Folgendes verwendet, um alle Dateien mit der Länge 0 zu löschen

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

Das ist komplizierter und nicht so effizient wie es sein könnte. Es ist viel einfacher, einfach zu benutzen:

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

Sie möchten eine bestimmte Datei löschen, wenn sie die Länge Null hat. Ersetzen Sie also einfach Ihren Dateinamen durch den Platzhalter *.

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

Wenn Sie dies in einer Batch-Datei verwenden möchten, müssen Sie alle Prozente verdoppeln (%%F, %%~zF)

Wenn Sie keine FOR-Schleife verwenden möchten, können Sie stattdessen einen CALL-Parameter verwenden, der dieselben Modifikatoren wie FOR-Variablen verwendet. CALL ist jedoch langsamer als FOR (in Ihrem Fall wahrscheinlich nicht signifikant)

@echo off
call :deleteIfEmpty "yourFileName"
exit /b

:deleteIfEmpty
if %~z1 eq 0 del %1
exit /b

BEARBEITEN

Ich habe mir noch einen anderen Weg überlegt. Eine FINDSTR-Suchzeichenfolge von "^" stimmt mit allen Zeilen einer Datei überein. Eine leere Datei enthält jedoch keine Zeilen. Löschen Sie die Datei einfach, wenn FINDSTR nicht mit einer Zeile übereinstimmt.

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

Ich habe es geschafft, ein Makro zu erstellen, das tatsächlich leere Dateien und leere Ordner löschen kann innerhalb einer Ordnerhierarchie.

Ich habe eine Weile gebraucht, um es auszuprobieren, aber jetzt funktioniert es:

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

Zunächst wird das Echo deaktiviert (entfernen Sie @ECHO OFF, wenn Sie lesen möchten, was tatsächlich passiert). Anschließend wird der aktuelle Ordner in der Variablen topLevel gespeichert. Als nächstes durchlaufen Sie alle Ordner "% D" mit dem Befehl FOR im aktuellen Ordner und allen Unterordnern. Es ändert das lokale Verzeichnis in jeden der gefundenen Unterordner (CD %% D). Innerhalb jedes Unterordners, der eine andere FOR-Schleife verwendet, werden alle Dateien %% F gefunden und gelöscht, deren Dateigröße (~ z für %% ~ zF) 0 ist. Wenn diese gesamte Dual-Schleife abgeschlossen ist, werden alle leeren Dateien effektiv von der Festplatte gelöscht. Nun wird ein neuer FOR-Befehl ausgeführt, um ein RD %% D zum Entfernen aller Verzeichnisse auszuführen. Da DOS hier sicher ist, werden nur leere Ordner gelöscht. Ordner mit darin enthaltenen Dateien bleiben intakt.

Aber hey, wer sagt, dass Sie nicht noch einmal verbessern können?

Ich habe das Skript noch einmal überarbeitet, jetzt stark optimiert für schnelle Verarbeitung :

@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

Das Problem mit der vorherigen war, dass die zwei verschachtelten FOR-Schleifen jede einzelne Datei berührten. Da leere Dateien selten sind, ist es absolut nicht erforderlich, jede Datei zu berühren, und es ist eine große Zeitverschwendung. Ich habe versucht, es auf einem 25-TByte-Volume mit ~ 5 Millionen Dateien auszuführen.

Daher habe ich die innere Schleife geändert, um Dateien in einem DIR-Befehl mit der Option/OS (Ordered Size) nach Größe zu sortieren. Die Option/A-D listet keine Verzeichnisse auf, daher verbleiben nur echte Dateien (Verzeichnisse werden auch als Größe 0 aufgeführt, deshalb habe ich dies hinzugefügt). Für jede Datei wird die Größe überprüft. Sobald eine Datei gefunden wurde, die größer als 0 Byte ist, wird die Schleife mit dem Befehl GOTO: break beendet. Da die Dateien nach Größe sortiert sind, ist es sicher, dass Sie so vorgehen. Ein riesiger Timesafer!

Da DOS FOR keine elegante Möglichkeit bietet, die Schleife zu verlassen, habe ich dieses seltsame Konstrukt verwendet, um die innere Schleife mit GOTO: break aufzurufen.

Es scheint ungefähr ein paar tausend Mal schneller auf meinem großen Volumen zu laufen als das vorherige ;-)

Ich hoffe du magst es!

Viele Grüße, Axel Mertes

PS: Der größte Albtraum bei DOS-Skripten ist das Verstehen, wann Sie %% oder%, 'oder "usw. benötigen.

4
Axel Mertes

Der Befehl forfiles ist möglicherweise besser:

echo

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

löschen

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

Tun Sie, was Sie wollen

4
joel Xu

Normalerweise würde ich mit FileSystemObject eine vbscript-Datei erstellen, die das Erkennen und Löschen der Datei handhabt, und diese über eine Batch-Datei ausführen.

VBScript-Datei:

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

Für die Batch-Datei:

cscript <filename>.vbs  
PAUSE
0
David Welker

einfach ist es, die Anzahl der Zeilen in der Datei mit zu finden

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

wenn die Anzahl jetzt Null ist, löschen Sie sie mit if-Bedingungen.

sie können die Schleife durch Dateien verwenden und nach allen Dateien in Ordnern suchen

0
Ashish