Borrar temporales[borrar archivos temporales de Windows y llevar la cuenta del número de archivos borrados]
Fecha: 04/Nov/2005 (3 de Noviembre de
2005)
|
Aspectos principales.
- Leer las variables de entorno TEMP y WINDIR
- Eliminar los archivos temporales
- Leer y escribir en un archivo de texto
- Iniciar un nuevo hilo o hebra (thread)
Resumen.
Durante varios años he utilizado un script de Visual Basic DeleteTempFiles.vbs, creado en 1999 por Michael Harris y modificado posteriormente por Bill James y Marcial Carlés. Este script funciona correctamente, borrando los archivos temporales de Windows e informando al usuario del tamaño de los archivos borrados (dato que guarda en un archivo de texto en el directorio de Windows).
Pero ha llegado el momento de plantear: ¿por qué no en .NET? Y el resultado es esta aplicación, inspirada en DeleteTempFiles.vbs en cuanto a su función principal y también en cuanto al mantenimiento de información en un archivo de texto. En lugar de guardar el tamaño, se guarda el número acumulado de los archivos borrados.En este ejercicio se propone una aplicación que borra los archivos temporales de Windows XP y la carpeta que los contiene, leyendo la variable de entorno TEMP, definida para el usuario de la sesión actual. Además, se muestra al usuario información sobre:
- número de archivos encontrados en la ejecución actual dentro de la carpeta TEMP
- número de archivos borrados en la ejecución actual (sólo se borran los archivos que no estén en uso)
- número total acumulado de archivos borrados por el programa desde su primera ejecución (leyendo este dato desde un archivo de texto colocado en C:\Windows)
El programa detecta si es la primera vez que arranca (comprobando si existe el archivo de texto que guarda el número de archivos borrados). Si es la primera vez, el programa crea el archivo de texto, informa de ello al usuario, se cierra y reinicia (mediante la creación de un segundo hilo y la finalización del actual).
Código Visual Basic .NET.
Se importan los espacios de nombres necesarios para las distintas funcionalidades del programa:
'manejo de archivos y carpetas Imports System.IO 'obtener variables de entorno Imports System.Environment 'tratar cadenas de texto (ejemplo: codificación usada al escribir en un archivo de texto) Imports System.Text 'proporciona clases e interfaces que permiten la programación multiproceso Imports System.ThreadingSe obtienen las rutas a los directorios Windows y Temp y al archivo de texto C:\Windows\Borrar_TEMP.txt con métodos de la clase Environment:
'ruta a la carpeta definida en la variable de entorno TEMP Protected rutaTemp As String = Environment.GetEnvironmentVariable("TEMP") 'ruta a la carpeta de sistema (WINDIR --> directorio de Windows) Protected rutaWindir As String = Environment.GetEnvironmentVariable("WINDIR") 'variable para la ruta completa al archivo de texto que registra el nº de archivos borrados Protected rutaTxt As String = rutaWindir & "\Borrar_TEMP.txt"Al cargar el formulario se configura la propiedad Form.CancelButton (obtiene o establece el control de botón que se activará cuando el usuario presione la tecla ESC) en el único botón de la ventana "OK (Esc)":
'al cargar el formulario Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load 'pulsar la tecla ESC equivale a pulsar el botón OK Me.CancelButton = Me.Button1 End SubLa primera vez que se ejecuta el programa, al comprobar que no existe el archivo de texto C:\Windows\Borrar_TEMP.txt, lo crea, informa al usuario de que el programa ha de reiniciarse para poder leer adecuadamente desde ese archivo, se cierra y vuelve a arrancar de forma automática; ésto se consigue creando un hilo (thread) y enlazándolo con el método nuevoForm() que arranca de nuevo la aplicación después de que ésta se haya cerrado en su hilo actual:
'comprobar si el archivo de registro existe (crearlo si no existe) Protected Sub archivoTxt() Dim archivo As New FileInfo(rutaTxt) 'si "Borrar_TEMP.txt" no existe --> crearlo e informar al usuario para que reinicie If archivo.Exists = False Then archivo.CreateText() Dim aviso As String aviso = "Se ha creado el archivo ""Borrar_TEMP.txt"" en la carpeta de Windows." & vbCrLf & _ "Es necesario reiniciar el programa para su correcto funcionamiento." & vbCrLf & _ "Pulsa ""Aceptar"" y el programa se cerrará y reiniciará automáticamente." MessageBox.Show(aviso, "Reiniciar el programa", MessageBoxButtons.OK) ' 'cerrar el formulario y que se vuelva a abrir automáticamente para que en el nuevo inicio 'lea correctamente desde el archivo Borrar_TEMP.txt y muestre la información ' 'crear un nuevo hilo (thread) que se enlaza con el método nuevoForm() 'que arrancará otra instancia diferente de Form1 Dim hilo As New Thread(AddressOf nuevoForm) hilo.Start() 'cerrar la aplicación y su hilo actual Application.Exit() ' 'si "Borrar_TEMP.txt" ya existe --> ejecutar el programa con normalidad Else 'llamar a los métodos: '- leer el nº de archivos del directorio y ' el nº acumulado de archivos borrados en "Borrar_TEMP.txt" Call listadoPre() '- leer el nº de archivos borrados en la ejecucion actual y escribir en "Borrar_TEMP.txt" Call listadoPost() End If End Sub 'método que inicia de nuevo la aplicación Public Shared Sub nuevoForm() 'detenerse 0,2 segundos Thread.Sleep(200) 'iniciar de nuevo la aplicación en el nuevo hilo Application.Run(New Form1) End SubEl método listadoPre():
- cuenta los archivos y carpetas del directorio TEMP antes del borrado. Para ello utiliza clases que permiten enumerar archivos en directorios y subdirectorios y otras operaciones típicas como copiar, mover, cambiar de nombre, crear y eliminar directorios: DirectoryInfo y FileSystemInfo.
- También lee desde el archivo de texto el número acumulado de archivos borrados en las ejecuciones anteriores del programa, usando la clase Stream.Reader que permite leer archivos de texto secuenciales.
- Finalmente, elimina el directorio TEMP usando el método DirectoryInfo.Delete que elimina una instancia de DirectoryInfo especificando si se van a eliminar los subdirectorios y los archivos (True o False):
'método que cuenta los archivos y las carpetas de TEMP antes del borrado Protected Sub listadoPre() Try 'variables para guardar el nº de archivos 'iCuentaTempPre = nº de archivos en la raíz de TEMP 'iCuentaSubdirPre = nº de carpetas en la raíz de TEMP 'iCuentaSubdirFilesPre = nº de archivos en las carpetas de la raíz de TEMP Dim iCuentaTempPre, iCuentaSubdirPre, iCuentaSubdirFilesPre As Integer 'la clase DirectoryInfo expone métodos de instancia para crear, mover y 'enumerar archivos en directorios y subdirectorios 'se utiliza para operaciones típicas como copiar, mover, cambiar de nombre, 'crear y eliminar directorios Dim dirTemp As New DirectoryInfo(rutaTemp) 'comprobar si el directorio existe If dirTemp.Exists = True Then 'contar los archivos de la raíz de TEMP (no en subdirectorios) iCuentaTempPre = dirTemp.GetFiles.Length 'contar todos los subdirectorios de TEMP Dim dirSub As FileSystemInfo() = dirTemp.GetDirectories() iCuentaSubdirPre = dirSub.Length 'contar todos los archivos de cada subdirectorio (sólo en el primer nivel de subdirectorios) Dim dirTemp2 As New DirectoryInfo(rutaTemp) For Each dirTemp2 In dirSub iCuentaSubdirFilesPre += dirTemp2.GetFileSystemInfos.Length Next 'mostrar información en la etiqueta de texto Me.Label1.Text = (iCuentaTempPre + iCuentaSubdirFilesPre).ToString 'valor de t = nº total de archivos encontrados antes de borrar TEMP iCuentaTempAll = (iCuentaTempPre + iCuentaSubdirFilesPre) ' 'leer el nº de archivos borrados hasta la fecha desde un archivo de texto guardado en %WINDIR% 'el archivo se llama C:\Windows\Borrar_TEMP.txt (siendo %WINDIR% = C:\Windows en este caso) 'las clases Stream.Reader y Stream.Writer permiten tratar con archivos de texto secuenciales Dim srLector As StreamReader 'variable para la primera línea del archivo de texto Dim sLinea As String ' 'leer la primera línea y pasarla a lCuentaBorrados srLector = New StreamReader(rutaTxt) sLinea = srLector.ReadLine lCuentaBorrados = CLng(sLinea) 'cerrar el archivo srLector.Close() ' 'el método DirectoryInfo.Delete elimina una instancia de DirectoryInfo 'especificando si se van a eliminar los subdirectorios y los archivos (True o False) 'se asigna al directorio de archivos temporales dirTemp.Delete(True) Else 'si no existe el directorio TEMP Me.Label1.Text = "0" Me.Label2.Text = "0" End If 'capturar excepciones Catch pollo As Exception 'pasar por alto la excepción si la causa es no poder borrar archivos por estar en uso (excepción System.IO.IOException) Dim sTipo As String sTipo = "System.IO.IOException" If Not pollo.GetType.ToString = sTipo Then MessageBox.Show(pollo.Message, "Aviso del programa", MessageBoxButtons.OK) Application.Exit() End If End Try End SubEl método listadoPost():
- cuenta los archivos y carpetas del directorio TEMP después del borrado, estos archivos son los que no han podido ser borrados por estar en uso. Para ello utiliza clases que permiten enumerar archivos en directorios y subdirectorios y otras operaciones típicas como copiar, mover, cambiar de nombre, crear y eliminar directorios: DirectoryInfo y FileSystemInfo.
- También suma el número de archivos borrados hasta la fecha y el número de archivos borrados en la ejecución actual, y escribe este dato en el archivo de texto usando la clase Stream.Writer que permite escribir en archivos de texto secuenciales.
- Finalmente, crea el directorio temporal en caso de que no exista ya que algunos programas arrancan con errores si no detectan la presencia del directorio definido en TEMP. Por ejemplo: Visual Studio da un error del compilador, Windows Media Player no inicia correctamente, etc:
'método que cuenta los archivos de TEMP después del borrado 'estos archivos son los que no han podido ser borrados porque están en uso Protected Sub listadoPost() Try 'variables para guardar el nº de archivos 'iCuentaTempPost = nº de archivos en la raíz de TEMP 'iCuentaSubdirPost = nº de carpetas en la raíz de TEMP 'iCuentaSubdirFilesPost = nº de archivos en las carpetas de la raíz de TEMP Dim iCuentaTempPost, iCuentaSubdirPost, iCuentaSubdirFilesPost As Integer 'la clase DirectoryInfo expone métodos de instancia para crear, mover y 'enumerar archivos en directorios y subdirectorios 'se utiliza para operaciones típicas como copiar, mover, cambiar de nombre, 'crear y eliminar directorios Dim dirTemp As New DirectoryInfo(rutaTemp) 'comprobar si el directorio existe If dirTemp.Exists = True Then 'contar los archivos de la raíz de TEMP (no en subdirectorios), iCuentaTempPost = dirTemp.GetFiles.Length ' 'ahora no hace falta contar los archivos de las subcarpetas pues el método 'dirTemp.Delete(True) las ha eliminado 'contar todos los subdirectorios de TEMP 'Dim dirSub As FileSystemInfo() = dirTemp.GetDirectories() 'iCuentaSubdirPost = dirSub.Length 'contar todos los archivos de cada subdirectorio (sólo en el primer nivel de subdirectorios) 'Dim dirTemp2 As New DirectoryInfo(rutaTemp) 'For Each dirTemp2 In dirSub ' iCuentaSubdirFilesPost += dirTemp2.GetFileSystemInfos.Length 'Next ' 'nº de archivos borrados hasta la fecha + nº de archivos borrados en la ejecución actual lCuentaBorrados = lCuentaBorrados + (iCuentaTempAll - iCuentaTempPost) ' 'escribir el nº de archivos en un archivo de texto guardado en %WINDIR% 'el archivo se llama C:\Windows\Borrar_TEMP.txt (siendo %WINDIR% = C:\Windows en este caso) 'las clases Stream.Reader y Stream.Writer permiten tratar con archivos de texto secuenciales Dim swEscritor As StreamWriter 'variable para la primera línea del archivo de texto Dim sLinea As String ' StreamWriter recibe 3 parámetros: '- String con la ruta al archivo '- True para añadir texto al existente, False para sobreescribir el texto existente '- codificación de caracteres que se utilizará (default: página de códigos ANSI usada por el sistema) swEscritor = New StreamWriter(rutaTxt, False, Encoding.Default) sLinea = CStr(lCuentaBorrados) 'escribir el valor de lCuentaBorrados en la primera línea swEscritor.WriteLine(sLinea) 'cerrar el archivo swEscritor.Close() ' 'mostrar información en la etiqueta de texto 'variable iCuentaTempAll --> total de archivos encontrados antes de borrar TEMP 'restándole los archivos no borrados por estar en uso --> archivos borrados realmente Me.Label2.Text = (iCuentaTempAll - iCuentaTempPost).ToString 'variable lCuentaBorrados --> nº de archivos borrados hasta la fecha + nº de archivos borrados en la ejecución actual If lCuentaBorrados = 0 Then Me.Label3.Text = "Ningún archivo" Else Me.Label3.Text = lCuentaBorrados.ToString("#,#") & " archivos" End If Else 'crear el directorio temporal en caso de que no exista 'algunos programas arrancan con errores si no detectan la presencia del directorio definido en TEMP 'por ejemplo: Visual Studio da error de compilador, Media Player no inicia correctamente... dirTemp.Create() Me.Label1.Text = "0" Me.Label2.Text = "0" End If 'capturar excepciones Catch pollo As Exception MessageBox.Show("AVISO: " & pollo.Message, "Aviso del programa", MessageBoxButtons.OK) Application.Exit() End Try End SubExiste una ayuda sencilla mediante un MessageBox con saltos de línea:
Private Sub PictureBox2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles PictureBox2.Click Dim ayuda As String = "Borra los archivos temporales y la carpeta que los contiene" & vbCrLf & _ "(variable de entorno TEMP, definida para el usuario actual)." & vbCrLf & vbCrLf & _ "Muestra al usuario información sobre:" & vbCrLf & _ "- Nº de archivos encontrados en la ejecución actual." & vbCrLf & _ "- Nº de archivos borrados en la ejecución actual." & vbCrLf & _ "- Nº total acumulado de archivos borrados por el programa" & vbCrLf & _ " (leyendo este dato desde un archivo de texto en C:\WINDOWS)." MessageBox.Show(ayuda, "Acerca de...", MessageBoxButtons.OK) End SubExcepciones al borrar archivos.
Nos interesan dos tipos de excepción que pueden aparecer cuando al programa no le es posible borrar algún archivo, lo que suele suceder por que el archivo está en uso o porque no se puede aceder a él por algún otro motivo. Se trata de las excepciones "System.IO.IOException" y "System.UnauthorizedAccessException"; es recomendable no capturar estas 2 excepciones en el método listadoPre() para no interrumpir el flujo del programa y evitar avisos de error:
'capturar excepciones Catch pollo As Exception 'pasar por alto la excepción si la causa es no poder borrar archivos por estar en uso ' (excepción System.IO.IOException o System.UnauthorizedAccessException) Dim sTipo1, sTipo2 As String sTipo1 = "System.IO.IOException" sTipo2 = "System.UnauthorizedAccessException" If Not pollo.GetType.ToString = sTipo1 And Not pollo.GetType.ToString = sTipo2 Then MessageBox.Show(pollo.Message, "Aviso del programa", MessageBoxButtons.OK) Application.Exit() End If End TryImagen del programa en funcionamiento.
Espacios de nombres usados en el código de este artículo:
System.IO
System.Environment
System.Text
System.Threading
Fichero con el código de ejemplo: miliuco_borrartemp.zip - 143 KB