2012-02-21 13 views
10

¿Cómo puedo detectar si un archivo está vacío usando un archivo por lotes de Windows? Quiero eliminar registros de errores si están vacíos.¿Cómo puedo detectar (y eliminar) un archivo si está vacío usando un archivo por lotes de Windows?

Estoy al tanto de las soluciones de bucle como http://anderwald.info/scripting/windows-batch-delete-all-empty-files-in-a-specified-folder/, pero me preguntaba si había una solución más elegante si conoce el único archivo específico en cuestión que debe probarse, ya que es posible que no desee eliminar otro cero byte archivos en la carpeta.

Respuesta

0

Normalmente crearía un archivo vbscript con FileSystemObject que manejaría la detección y eliminación del archivo, y lo ejecutaría desde un archivo por lotes.

Archivo 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 

Para el archivo por lotes:

cscript <filename>.vbs 
PAUSE 
24

El enlace que citó utilizó el siguiente para eliminar los 0 archivos de longitud

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

Eso es más c complicado y no tan eficiente como podría ser. Es mucho más fácil de usar, simplemente:

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

que desea borrar un archivo específico si es cero longitud. Así que simplemente sustituya su nombre de archivo por el comodín *.

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

Si se van a usar esto en un archivo por lotes de lo que necesita para duplicar todos los porcentajes (%%F, %%~zF)

Si no desea utilizar un bucle FOR, puede utilizar un parámetro CALL en su lugar - usa los mismos modificadores que las variables FOR. Sin embargo, CALL es más lenta que para (probablemente no es significativa en su caso)

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

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

EDITAR

he pensado de otra manera. Una cadena de búsqueda FINDSTR de "^" coincidirá con todas las líneas de un archivo. Pero un archivo vacío no tiene líneas. Así que simplemente elimine el archivo si FINDSTR no puede coincidir con una línea.

>nul findstr "^" "yourFileName" || del "yourFileName" 
+0

Hmmm ... Así que pensé en esto también , usando un bucle for para solo una iteración en mi archivo. Esperaba que haya algo más elegante que esto, pero esto servirá. – Xonatron

+0

@MatthewDoucette Agregué una alternativa usando CALL en lugar de FOR – dbenham

+0

@MatthewDoucette - He agregado aún otro método usando FINDSTR.También arreglé un error tonto en la solución CALL (demasiados puntos en la etiqueta). – dbenham

4

El comando forfiles podría ser más agradable, así:

eco

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

eliminar

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

hacer lo que quiera

+1

FORFILES no está disponible universalmente para todas las versiones de Windows. También es muy S L O W. . . . – dbenham

+0

@dbenham Es cierto, pero tiene una gran ventaja en esta solución: puede especificar el tamaño de archivo que necesita. También puede encontrar archivos "vacíos"/inútiles con un tamaño de 4 o 5 bytes (solo incluye un CR o CR/LF u otro carácter de control además de un UTF-8-BOM). Sé que 1 o 2 bytes también podría incluir A o ZZ, pero esto sería inútil como archivo de registro también .-) – PeterCo

0

sencilla es encontrar el número de líneas en el archivo usando

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

ahora si su recuento es cero y luego elimine usando if conditions.

puede utilizar el bucle a través de los archivos y comprobar si todos los archivos en carpetas

4

que he conseguido hacer una macro que en realidad puede borrar archivos y carpetas vacías vacías dentro de una jerarquía de carpetas.

que me tomó un tiempo para tocar el violín a cabo, pero ahora funciona:

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

Primero se desactiva haciendo eco (quitar @ECHO OFF si desea leer lo que realmente sucede). Luego almacena la carpeta actual en la variable topLevel. Lo siguiente es recorrer todas las carpetas "% D" utilizando el comando FOR en la carpeta actual y todas las subcarpetas. Cambia el directorio local a cada una de las subcarpetas encontradas (CD %% D). Dentro de cada subcarpeta usando otro bucle FOR encuentra y borra todos los archivos %% F para los cuales el tamaño del archivo (~ z para %% ~ zF) es 0. Cuando todo este bucle doble finaliza, todos los archivos vacíos son efectivamente eliminados del disco. Ahora se ejecuta un nuevo comando FOR para realizar un RD %% D para eliminar todos los directorios. Debido a que DOS está a salvo aquí, eliminará solo las carpetas VACÍAS. Las carpetas con archivos dentro se mantienen intactas.

Pero, ¿quién dice que no puede mejorar una vez más?

Hemos modificado la secuencia de comandos, una vez más, ahora muy optimizado paraprocesamiento rápido:

@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 

El problema con el anterior era que los dos bucles for anidados tocado cada fila india. Como los archivos vacíos son raros, no hay absolutamente ninguna necesidad de tocar cada archivo y es una gran pérdida de tiempo. Intenté ejecutarlo en un volumen de 25 TByte con ~ 5 millones de archivos ...

Modifiqué el bucle interno para ordenar archivos por tamaño en un comando DIR utilizando la opción/OS (Tamaño ordenado). La opción/A-D no muestra directorios, por lo que solo quedan archivos verdaderos (los directorios también se muestran como tamaño 0, por eso lo agregué). Para cada archivo, se verifica el tamaño. Una vez que se encuentra un archivo de más de 0 bytes, el ciclo se cierra usando GOTO: break. Como los archivos están ordenados por tamaño, el más pequeño primero, es seguro proceder de esta manera. ¡Un gran ahorro de tiempo!

Como el comando DOS FOR no tiene una forma elegante de abandonar el bucle, utilicé este extraño constructo para llamar al bucle interno usando GOTO: break.

parece correr sobre unos pocos miles de veces más rápido en mi gran volumen que el anterior ;-)

espero que les guste!

Saludos, Axel Mertes

PS: La pesadilla más grande en el DOS es la comprensión de secuencias de comandos cuando se necesita o %%%, 'o "etc.

+0

Su versión optimizada está muy bien hecha, sin embargo, no es una respuesta a la pregunta. El OP preguntó explícitamente cómo probar y eliminar un único archivo específico, no una jerarquía completa. Además, ha desarrollado un script por lotes, no una macro. – dbenham

Cuestiones relacionadas