COPIAS DE RESPALDO

GuardaCopia:

Frecuentemente nos encontramos con alguien que (por error, fallo del sistema, o por… otros motivos) ha perdido datos importantes y pregunta cómo podría recuperarlos.

La solución no deberíamos buscarla después de, sino más bien antes de que ocurra. Más vale prevenir que curar.

Eso y que recientemente el caso ha ocurrido en mí entorno familiar, me ha llevado a elaborar el código VBA que está más abajo y que almacenándolo en PERSONAL.XLSB para el ejemplo Excel y/o en NORMAL para el ejemplo Word, permite guardar una copia en otra carpeta (MisCopias), con el mismo nombre + día + mes + hora actual.

Con el guardar con copia tradicional, cada vez que guardamos cambios machacamos los archivos existentes con la nueva información, tanto el original como la copia. Con esta solución que ofrezco aquí, al guardar machacamos igualmente la información del fichero original pero la copia queda intacta y se añade una copia nueva, con lo que podríamos dar “marcha atrás” y recuperar una versión anterior.

¡Ojo! Si guardamos dos veces en la misma fecha y hora (mismo minuto), la copia sería una sola (la última) ya que la hora está compuesta solamente de horas y minutos y por tanto los nombres serían iguales.

Si utilizas este método con un fichero nuevo que no ha sido guardado previamente, se muestra el cuadro de diálogo GUARDAR COMO, donde deberás asignar un nombre para el fichero y elegir el tipo Habilitado para macros .

Si el fichero que quieres guardar no está habilitado para macros (xlsx o docx), muestra un mensaje de aviso con dos opciones:
SI = Habilitar para macros.
NO = No guardar copia.

Si la subcarpeta "MisCopias" no existe en la ubicación donde guardas el fichero, el código VBA la crea antes de guardar los cambios, para depositar en ella las copias que se generan.

Ejemplo de nombres de copias guardadas en Word (obviamente; para Access, Excel, o versiones anteriores, cambiaría la extensión):

COPIAS DE RESPALDO.docm
COPIAS DE RESPALDO 26feb 11•10.docm.

Observa el símbolo separador de horas y minutos (en mi teclado: Mayúscula + 3). El código VBA realiza la sustitución, debido a que el carácter “dos puntos” (:) no está permitido en nombres de archivo.

Construcción del ejemplo:

Una vez tengamos el código en un módulo ordinario de PERSONAL.XLSB o en NORMAL, podemos añadir un icono a la Barra de acceso rápido, similar a como se muestra en la figura de la derecha, puede ser cualquier icono de la colección.

Para añadir el código podemos utilizar dos métodos:
1.- En un módulo ordinario copia/pega el código que ofrezco.
2.- Haz clic con botón secundario sobre el módulo ordinario, elige importar archivo y elige el módulo de la descarga que previamente habrás almacenado en tu disco duro.

- CopiasE.bas es el módulo para Excel y CopiasW.bas es el módulo para Word.

El procedimiento para insertar el icono en la Barra de acceso rápido lo muestro a continuación:
    1.- Modifica la primera línea de código, borrando lo que está entre paréntesis...
           de: Sub GuardaCopia(Optional nada&) 
            a: Sub GuardaCopia() 
        ... para que puedas ver la macro en el punto 6.
        Cuando hayas añadido el icono, deja la línea como estaba si no quieres que se vea en el listado de macros.
    2.- Pulsa el Botón de Office (arriba a la izquierda).
    3.- Pulsa Opciones de Excel (para otros entornos Office, el proceso es similar).
    4.- Elige Personalizar.
    5.- Despliega Comandos disponibles en: y elige Macros.
    6.- Entre las macros disponibles elige GuardaCopia.
    7.- Puedes ubicar el icono donde prefieras (flechas a la derecha).
    8.- Pulsa Modificar.
    9.- Puedes sustituir el icono que tomó por defecto, por el que creas oportuno y modificar el texto que se muestra
        cuando señalas con el cursor en el icono.
    10.- Pulsa ACEPTAR dos veces.
    11.- Guarda los cambios.
Este método además de asegurar la integridad de la(s) copia(s) anterior(es), permite retroceder a la información existente ayer por la tarde, hace 4 días, etc. siempre que la copia que necesitamos sea una de las tres últimas, que es el tope de copias que el código VBA permite. En el caso de que queramos conservar un número mayor (o menor) de copias, podemos hacerlo modificando el número en la penúltima linea del módulo CuentaCopias.

Nota: Estos ejemplos son para Excel y Word, para la versión de Office 2007 o superior. Para otros entornos de Office o para versiones anteriores, será necesario modificar el código que ofrezco. Para ello puede servir de guía las diferencias entre las dos versiones que expongo. Las diferencias son pocas; en una trabajamos con libros (.xlsm) y en la otra trabajamos con documentos (.docm).




Volver arriba


Código VBA para Excel:

     '—————————————————————————————————————————————————————————————————————————————————————
     ' Guardo el libro actual y una copia del mismo, con el mismo         º   º º º       /
     ' nombre más la fecha y hora actual, en la carpeta "MisCopias".     / \ º     \     /
     ' Si la carpeta no existe el código VBA la crea.                   /   \ º º º \   /
     ' Si ya existen 5 copias o más, muestro un mensaje de aviso.      /     \     º \ /
     '            Febrero de 2012.                                    /       º º º   º
     '—————————————————————————————————————————————————————————————————————————————————————
GuardaCopia
     Sub GuardaCopia(Optional nada&) 'Excel superior a 2003.
       Dim ruta$, nombre$, nombreC$, punto&, resp&, numC&
       On Error GoTo Errores 'Control de errores.
       nombre = ActiveWorkbook.Name 'Nombre del archivo actual.
       punto = InStr(nombre, ".") 'Posición del punto.
       If punto = 0 Then ActiveWorkbook.Save 'Si no tiene extensión (no se ha guardado), _
           muestro el cuadro de diálogo GUARDAR COMO.
          resp = 6 'Valor por defecto para guardar la copia.
          ruta = ActiveWorkbook.Path 'Ruta del libro actual.
          nombre = "\" & ActiveWorkbook.Name 'Nombre del libro actual.
          punto = InStr(nombre, ".") 'Posición del punto.
          If Mid(nombre, punto) = ".xlsx" Then 'Si el libro no está habilitado para macros...
           resp = MsgBox("Para guardar Copia con nombre+Fecha es preciso " & vbCr & _
               "habilitar el libro para macros." & vbCr & vbCr & _
               "SI = Habilitar para macros." & vbCr & "NO = No guardar copia.", _
               vbYesNo, "AnSanVal") 'Mensaje informativo.
            If resp = vbYes Then nombre = Left(nombre, punto) & "xlsm" 'Extensión de libro _
              habilitado para macros.
       End If 'Mid(nombre...
       nombreC = "\MisCopias" & Left(nombre, punto - 1) & Replace(Format(Now, " ddmmm hh:mm"), _
           ":", "•") & ".xlsm" 'Nombre para la copia.
       If Dir(ruta & "\MisCopias\", vbDirectory) = "" Then MkDir ruta & "\MisCopias\" 'Si _
           no existe la carpeta "MisCopias"; la crea.
       If resp = vbYes Then Guardar ruta & nombreC 'Guardo con nombre + fecha.
       Guardar ruta & nombre 'Guardo con nombre "simple".
       CuentaCopias ruta & "\MisCopias\", Mid(Left(nombre, punto - 1), 2) ' _
           Si existen más de 3 copias borro la más antigua.
       Exit Sub 'Fin del proceso.
     Errores: 'Control de errores.
       If Err.Number = 4198 Then Exit Sub 'Guardado cancelado.
       MsgBox "Error: " & Err.Number & " " & Err.Description 'Error no controlado.
     End Sub 'GuardaCopia

Guardar
     Sub Guardar(nombre$)
       Application.DisplayAlerts = False 'Desactivo "Mostrar mensajes".
       ActiveDocument.SaveAs FileName:=nombre, FileFormat:= _
         wdFormatXMLDocumentMacroEnabled, LockComments:=False, Password:="", _
         AddToRecentFiles:=True, WritePassword:="", ReadOnlyRecommended:=False, _
         EmbedTrueTypeFonts:=False, SaveNativePictureFormat:=False, _
         SaveFormsData:=False, SaveAsAOCELetter:=False 'Guardo documento o copia.
       Application.DisplayAlerts = True 'Activo "Mostrar mensajes".
     End Sub 'Guardar

CuentaCopias
     Sub CuentaCopias(ruta$, nombre$)
       Dim archivo$, num&, archViejo$, miFecha As Date
       archivo = Dir(ruta & nombre & "*") 'Busco la primera coincidencia.
       miFecha = Now 'Fecha y hora actual.
       Do While archivo <> ""
         If FileDateTime(ruta & archivo) < miFecha Then 'Si fecha de archivo es menor...
           miFecha = FileDateTime(ruta & archivo) 'Fecha del archivo leido.
           archViejo = ruta & archivo 'Ruta y nombre del archivo leido.
         End If 'If FileDateTime...
         num = num + 1 'Incremento el contador.
         archivo = Dir() 'Busco coincidencia siguiente.
       Loop
       If num > 3 Then Kill (archViejo) 'Borro el más antiguo?
     End Sub 'CuentaCopias


Volver arriba


Código VBA para Word:

     '—————————————————————————————————————————————————————————————————————————————————————
     ' Guardo el documento actual, y una copia del mismo con el           º   º º º       /
     ' mismo nombre más la fecha y hora actual, en la carpeta            / \ º     \     /
     ' "MisCopias". Si la carpeta no existe; la creo.                   /   \ º º º \   /
     ' Si ya existen 5 copias o más, muestro un mensaje de aviso.      /     \     º \ /
     '            Febrero de 2012.                                    /       º º º   º
     '—————————————————————————————————————————————————————————————————————————————————————
GuardaCopia
     Sub GuardaCopia(Optional nada&) 'Word superior a 2003.
       Dim ruta$, nombre$, nombreC$, punto&, resp&, numC&
       On Error GoTo Errores 'Control de errores.
       nombre = ActiveDocument.Name 'Nombre del archivo actual.
       punto = InStr(nombre, ".") 'Posición del punto.
       If punto = 0 Then ActiveDocument.Save 'Si no tiene extensión (no se ha guardado), _
           muestro el cuadro de diálogo GUARDAR COMO.
       resp = 6 'Valor por defecto para guardar copia.
       ruta = ActiveDocument.Path 'Ruta del documento.
       nombre = "\" & ActiveDocument.Name 'Nombre del archivo actual.
       punto = InStr(nombre, ".") 'Posición del punto.
       If Mid(nombre, punto) = ".docx" Then 'Si el doc. no está habilitado para macros...
         resp = MsgBox("Para guardar Copia con nombre+Fecha es preciso " & vbCr & _
                       "habilitar el documento para macros." & vbCr & vbCr & _
             "SI = Habilitar para macros." & vbCr & "NO = No guardar copia.", _
             vbYesNo, "AnSanVal") 'Mensaje informativo.
         If resp = vbYes Then nombre = Left(nombre, punto) & "docm" 'Extensión de _
             documento con macros.
       End If
       nombreC = "\MisCopias" & Left(nombre, punto - 1) & Replace(Format(Now, " ddmmm hh:mm"), _
           ":", "•") & ".docm" 'Nombre para la copia.
       If Dir(ruta & "\MisCopias\", vbDirectory) = "" Then MkDir ruta & "\MisCopias\" 'Si _
           no existe la carpeta; la crea.
       If resp = vbYes Then Guardar ruta & nombreC 'Guardo con nombre + fecha.
       Guardar ruta & nombre 'Guardo con nombre "simple".
       numC = CuentaCopias(ruta & "\MisCopias\" & Mid(Left(nombre, punto - 1), 2))
       If numC > 4 Then Mensaje ruta, numC, nombre 'Recomendación.
       Exit Sub 'Fin del proceso.
     Errores: 'Control de errores.
       If Err.Number = 4198 Then Exit Sub 'Guardado cancelado.
       MsgBox "Error: " & Err.Number & " " & Err.Description 'Error aún no controlado.
     End Sub 'GuardaCopia

Guardar
     Sub Guardar(nombre$)
       Application.DisplayAlerts = False 'Desactivo "Mostrar mensajes".
       ActiveDocument.SaveAs FileName:=nombre, FileFormat:= _
         wdFormatXMLDocumentMacroEnabled, LockComments:=False, Password:="", _
         AddToRecentFiles:=True, WritePassword:="", ReadOnlyRecommended:=False, _
         EmbedTrueTypeFonts:=False, SaveNativePictureFormat:=False, _
         SaveFormsData:=False, SaveAsAOCELetter:=False 'Guardo documento o copia.
       Application.DisplayAlerts = True 'Activo "Mostrar mensajes".
     End Sub 'Guardar

CuentaCopias
     Sub CuentaCopias(ruta$, nombre$)
       Dim archivo$, num&, archViejo$, miFecha As Date
       archivo = Dir(ruta & nombre & "*") 'Busco la primera coincidencia.
       miFecha = Now 'Fecha y hora actual.
       Do While archivo <> ""
         If FileDateTime(ruta & archivo) < miFecha Then 'Si fecha de archivo es menor...
           miFecha = FileDateTime(ruta & archivo) 'Fecha del archivo leido.
           archViejo = ruta & archivo 'Ruta y nombre del archivo leido.
         End If 'If FileDateTime...
         num = num + 1 'Incremento el contador.
         archivo = Dir() 'Busco coincidencia siguiente.
       Loop
       If num > 3 Then Kill (archViejo) 'Borro el más antiguo?
     End Sub 'CuentaCopias


Volver arriba